Closed osrf-migration closed 3 years ago
Original comment by Steve Peters (Bitbucket: Steven Peters, GitHub: scpeters).
This is a summary of my off the cuff opinions about parts of your proposal.
Proposal | Cost | Benefit |
---|---|---|
Put warning suppression macros in header installed from ign-cmake | install an extra file, unlikely to affect API/ABI, easy | code easier to read |
Put Implementation class in header file installed from ign-cmake | still just installing a header file, but any changes could affect API/ABI | easier to implement move semantics |
Put Console class in ign-cmake | requires compiling and distributing a library with ign-cmake | easier to print consistent console warnings |
Rename ign-cmake | lots of work | subjective |
I could easily be convinced of the first two rows since they are header-only; I'm skeptical of putting compiled code in ign-cmake, and I'm even more skeptical about renaming ign-cmake
from a cost/benefit perspective.
Original comment by Michael Grey (Bitbucket: mxgrey, GitHub: mxgrey).
Thanks for the chart, I think that's a very helpful overview. Just a few comments on it:
Warning suppression will definitely never affect API or ABI since it only introduces compiler directives that relate to whether or not specific warnings get emitted by the compiler. They have zero effect on how the code itself gets interpreted. Any warning suppression methods that go beyond that would be outside the scope of the suppression macros.
Besides "easiness", I'd like to emphasize that this would provide a more consistent experience for developers and for (in the case of Console) users across all the ignition projects.
It wouldn't be very difficult to make the Console code header-only if we wanted to go that route. It's probably not the most efficient design, but the Console isn't a terribly heavy feature, so I don't think it would have a noticeable impact on compilation time or code size.
The renaming isn't a critical part of the proposal. I'm mostly indifferent about it, but I'd encourage it if we were willing to do it.
A few months after this issue was ticketed, the utilities component was added to ign-cmake
with the suppression warnings.
3 years later, on Ignition Edifice, we added the ign-utils package to serve this purpose, so we don't stretch the responsibility of ign-cmake
and it can remain focused on build utilities. The ign-utils
package is already used by libraries that don't directly depend on ign-cmake
, like libSDFormat
.
The PIMPL pointer helper is already on ign-utils
, as well as the suppression macros. See #171 about deprecating the utilities in this repository.
I'm closing this issue in favor of putting new C++ utilities into ign-utils
.
Original report (archived issue) by Michael Grey (Bitbucket: mxgrey, GitHub: mxgrey).
Apologies in advance for the wall-of-text.
The original motivation for creating
ign-cmake
was to systematically ensure consistent build behavior across all the ignition projects, in a way that is maintainable and scalable.Even though the
ign-cmake
package is still in development, it's had some very tangible benefits: we now have four projects (ign-math
,ign-common
,ign-msgs
, andign-transport
) with robust build systems across all of our supported platforms and consistent package behavior across all of the projects. If we ever decide to change our packaging behavior or if we ever need to fix a build system bug, we can take care of it inign-cmake
, and all the ignition projects will benefit the next time they configure. Future and upcoming projects will experience these benefits as well.However, we want to have consistency across all the ignition projects in more ways than just their build system and packaging. The most obvious example is the PIMPL pattern, which is a design pattern that we aim to use across all the ignition projects to achieve maximum flexibility in our development cycles without needing to be concerned about breaking ABI.
The forcing function that prompted me to make this proposal was in a recent
ign-transport
pull request, we found ourselves repeatedly writing boilerplate move and copy constructors, plus move and copy assignment operators for just about every darn interface class (here's a sampling from that one pull request: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19).The worst part is, even with all that effort in manually creating all those constructors and assignment operators, some of the classes in that pull request still don't have proper copy and move semantics, simply because we have not yet noticed that their copy/move constructors/operators are missing.
That's when I remembered some design utilities promoted by Scott Meyers which makes the PIMPL pattern so very much more bearable. Here's a tl;dr of that article:
Instead of using a plain
std::unique_ptr<Implementation>
to contain the implementation object, you can have aimpl_ptr<Implementation>
which takes care of creating the copy and move constructors for your interface class. To make that more concrete, your class definition would look like this:Then in the source file, your constructor would look like this:
This will allow
MyClass
to automatically create a copy constructor, move constructor, copy operator, and move operator, and all you have to do is replacestd::unique_ptr
withImplPtr
andnew Implementation
withMakeImpl<Implementation>
. Note that we can also have aUniqueImplPtr
which will allow moving but not copying, for classes that are not copyable. The catch, of course, is you need to have access to the header that definesImplPtr
andMakeImpl
.Since it's a single header file, the brute force approach would be to write the header and then drop it into each project. That's a viable solution if we're confident that we'll never ever have to make any changes to the implementation, but that's a very risky assumption to make.
Ideally, we would want the
ImplPtr
to be available in every project from a single source. We already have a project which is a required dependency of every ignition project:ign-cmake
. If we were to consider the goal ofign-cmake
to be achieving consistent, maintainable, scalable development (not just build+packaging behavior) across all the ignition projects, then it would make sense to have it provide a small set of C++ utilities that could be used across all projects to keep behavior and development consistent between them.I can think of three utilities which would make sense to share across all projects right away: (1) the pimpl class mentioned here, (2) the warning suppression system which is currently in
ign-common
, and (3) the Console utility currently inign-common
. These are things that all project would benefit from:Anything that can make PIMPL easier to stomach is a good thing.
We're repeatedly dealing with the same compiler warnings across every project. This would give us a clean way to handle those consistently everywhere.
Having the
Console
class and its error/warning macros as base utilities would allow us to have consistent status, warning, and error messaging behavior across all the libraries, instead of having some print proper messages while others print plain, unformatted messages.We could also consider the
Filesystem
fromign-common
, but I don't think that's as basic of a utility (and it will probably be replaced by the C++17 filesystem soon anyway).Why not just use ign-common?
Right now,
ign-common
would be more aptly namedign-miscellaneous
. Most of its content is not common to all projects, and it would be unreasonable to have all projects depend on it, even after it's been split into components.ign-cmake
is already a required dependency. Putting these utilities intoign-cmake
will make them accessible to all projects right away, without introducing any new dependencies.Then could we really call this project ign-cmake anymore?
Maybe not.
I would propose that we add these utilities to
ign-cmake
as a library calledignition-utilities
(or maybeignition-utils
, or some variation on that). When each project callsfind_package(ignition-cmake1)
it will import a target for theignition-utilities
library, andign-cmake
can automatically link each project library against the utilities target. Consumer projects wouldn't have to change anything in their build scripts.Then, when we're approaching the hypothetical release of
ignition-cmake1
, we can decide whether we want to keep using the nameignition-cmake
. Maybe by then,ign-common
will be rid of its miscellaneous components, and we can haveign-cmake
take over the nameign-common
. Otherwise, we could consider renamingign-cmake
to something likeign-utilities
,ign-utils
,ign-root
,ign-base
, or any other suggestions that people have. Or we could just keep the name asign-cmake
and accept the slight misnomer of the project.