The Beman Standard CMake requirements and recommendations are in good shape, I would like to propose adding two more recommendations to guide the existing projects as we prepare them for packaging.
Proposal
[CMAKE.IMPLICIT_DEFAULTS] RECOMMENDATION: Where CMake commands have reasonable default values, and the project does not intend to change those values, the parameters should be left implicitly defaulted rather than enumerated in the command.
Example:
# Not recommended
# Explicitly enumerated defaults for install artifact destinations
install(
TARGETS beman.project
EXPORT beman.project-targets
DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME
DESTINATION ${CMAKE_INSTALL_BINDIR}
FILE_SET HEADERS
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
# Recommended, implicit defaults
install(
TARGETS beman.project
EXPORT beman.project-targets
FILE_SET HEADERS
)
[CMAKE.NO_SINGLE_USE_VARS] RECOMMENDATION: set()
should not be used to create variables that are only used once. Prefer using the value(s) directly in such cases.
Example:
# Not recommended, single-use variable for the source list
set(SOURCES
a.cpp
b.cpp
c.cpp
)
# ...
target_sources(beman.project PRIVATE ${SOURCES})
# Recommended, list sources directly
target_sources(beman.project
PRIVATE
a.cpp
b.cpp
c.cpp
)
Rationale
[CMAKE.IMPLICIT_DEFAULTS]
CMake commands are complicated messes of fractal-like context specific syntax. When it comes to the more complicated commands like target_sources()
and install()
, less is definitely more.
When non-experts (which is most C++ programmers) have to edit a CML, they reasonably assume that everything in there was written for a reason. Enumerated defaults leave even build system veterans scratching their heads wondering what problem a given parameter was trying to solve. This leads to a Chesterton’s Fence scenario where developers are afraid to touch code they don’t understand.
Leaving defaults implicit increases CMake code clarity, readability, and allows developers to be more confident in making changes.
[CMAKE.NO_SINGLE_USE_VARS]
This is a simple locality problem. Code isn’t any shorter when creating these single-use variables, all it does is frustratingly decouple description from use.
This pattern is a holdover from ancient CMake days when such variables would actually be used a couple of times for reasons that are esoteric and boring to explain. It’s been 15 years since such patterns were relevant, and these style of variables are now thoroughly discouraged by the CMake orthodoxy.
Bonus: I really don’t like it when devs create a variable to hold a single short constant string that’s about the same length as the variable name. Just use the string. I don’t dislike it enough to codify it though.