Release Date: 16th August 2024
This is part of the change history for the book Professional CMake: A Practical Guide. The 19th Edition has been updated for the CMake 3.30 release and for Qt 6.7. The main new CMake feature covered in this edition is the new FetchContent behavior that avoids a sub-build. This is a potential big performance gain for large projects with many dependencies. The new translations APIs added in Qt 6.7 are another significant update for this edition.
The book has grown in size, and some parts are fairly verbose. In addition, the number one piece of reader feedback is for more examples. The main focus of this edition has been to begin addressing these two things. The first 18 chapters (parts 1 and 2 of the book) have been reviewed and reworked in this edition, and this work will continue in future editions for the remaining chapters.
Setup Project chapter:
- Updated examples to use
cmake -B build ...
instead of manually making and changing to thebuild
directory first.
Building Simple Targets chapter:
- Added an example to the Executables section for
add_executable()
showing the effect of theEXCLUDE_FROM_ALL
keyword and a motivating case for why you might want to use it. - Updated the wording and advice in the Linking Non-targets section. Policy
CMP0060
is no longer mentioned, advice for plain library names now cross-references the chapter that talks about requiring target names for linking, and the link flags item advises against using them and to use the dedicated support for adding such flags instead (with cross-references to the relevant sections). - The Old-style CMake section now mentions policy
CMP0023
when discussing what happens when mixing the keyword and non-keyword forms oftarget_link_libraries()
. - Updated examples to use
cmake -B build ...
instead of manually making and changing to thebuild
directory first.
Basic Testing And Deployment chapter:
- Added a brief mention of the
CMAKE_TEST_ARGUMENTS
variable when discussing how to runctest
via thetest
build target. - Updated examples to use
cmake -B build ...
instead of manually making and changing to thebuild
directory first.
Variables chapter:
- The String Handling and Lists sections were reworked to have less text, and to use more examples instead of formal command syntax for
string()
andlist()
. Related examples were also combined to reduce verbosity, and these sections now avoid repeating a lot of the command details that are already clearly explained in the official CMake reference documentation for these two commands.
Flow Control chapter:
- Added an example demonstrating a common trap with how the
if()
command can treat an unquoted value as a string or a variable name, depending on whether a variable by that name exists. Guidelines were also added to help avoid running into problems related to this behavior. - Added a brief discussion and example for how the
if(COMMAND)
form can be useful for checking the availability of a command provided by a third party as a technology preview. Simple examples were also added forif(POLICY)
andif(TARGET)
. - Mention that
if(TEST)
can only be used if policyCMP0064
is set toNEW
. - Updated the example for
if(IN_LIST)
to also show the older, more verbose logic based onlist(FIND)
for when policyCMP0057
cannot be assumed to beNEW
. - Updated the example in the Interrupting Loops subsection to use
set(s "")
instead ofunset(s)
. This is more robust, since it doesn’t rely on there not being a cache variable nameds
. - The Recommended Practices section was updated to explicitly mention ensuring policy
CMP0054
is set toNEW
as part of setting the minimum CMake version.
Functions And Macros chapter:
- Updated examples involving
cmake_parse_arguments()
to use lowercasearg
as the variable prefix instead of other uppercase values likeARG
. This makes it easier to visually spot any use of the resultant variables instead of them looking like cache variables or keywords. - Discussion and examples of tracking deferred commands using
cmake_language(DEFER)
via their ID have been removed. This is a very advanced topic that few projects need, and it made the rest of the material related tocmake_language(DEFER)
seem more complicated. That part of the Other Ways Of Invoking CMake Code section now focuses on the more common uses ofcmake_language(DEFER)
. - Added a paragraph to the Recommended Practices section warning against implementing overly complex keyword and argument parsing with
cmake_parse_arguments()
. The advice highlights that this is often a sign of a function or macro having too many responsibilities.
Properties chapter:
- Added examples to the General Property Commands section showing calls to
set_property()
andget_property()
for the various property types. Examples were also added showing how the inheriting behavior ofget_property()
works for target and directory properties, including how it interacts withset_property()
. - Added an example to the Global Properties section for
get_cmake_property()
. - Added an example to the Directory Properties section to demonstrate the pros and cons of
set_property(DIRECTORY)
versus set_directory_properties()
. An example was also added forget_directory_property()
. - Added examples to the Target Properties section for
set_target_properties()
andget_target_property()
. An explanation was also added for an important difference in behavior betweenget_property(TARGET)
andget_target_property()
for an unset property. - Added an example to the Source Properties section for
set_source_files_properties()
, showing how to handle calls in a different directory scope. This section also now highlights behavior differences betweenget_property(SOURCE)
andget_source_file_property()
for an unset property. - Added an example to the Cache Variable Properties section showing all cache variable properties being set by their more typical commands.
- Added an example to the Test Properties section, showing how to manipulate test properties across different directories.
Generator Expressions chapter:
- Mention that
$<CONFIG:...>
is a case-insensitive comparison. - Added examples for
$<TARGET_PROPERTY:...>
and$<TARGET_FILE_NAME:...>
to the Target Details section. - Added an example to the List Expressions section showing a few commonly used sub-expressions for
$<LIST:...>
. - Added an example to the Utility Expressions section for
$<COMMA>
. The section was also updated for the new$<QUOTE>
generator expression added in CMake 3.30.
Policies chapter:
- Added an example to the Policy Control section showing how to use
CMAKE_POLICY_DEFAULT_CMPxxxx
variables to enable the new FetchContent direct population behavior globally.
Debugging And Diagnostics chapter:
- Added an example to the Tracing Variable Access section showing how to define a command to receive
variable_watch()
events. - Added mention of Perfetto to the list of tools for viewing profiling information mentioned in the Recommended Practices section.
Build Type chapter:
- Updated an example in the Common Errors section that shows wrong use of
CMAKE_BUILD_TYPE
to set a compiler definition, and added a second example showing how to do it correctly using a$<CONFIG:...>
generator expression. - Updated the examples and text in the Custom Build Types section to no longer show enforcing the configuration to be one of a predefined set of values. Developers should be free to add their own new build types.
- Updated examples to use
cmake -B build ...
instead of manually making and changing to thebuild
directory first.
Compiler And Linker Essentials chapter:
- Updated an example in the Linker Flags section to use
set_property(TARGET)
instead ofset_target_properties()
so that it can use theAPPEND
keyword to add to the existing linker options, not replace them. - Added a discussion and example to the Linking Libraries subsection explaining the behavior of
PRIVATE
with static and object libraries. - Slightly reordered parts of the Linker Options subsection to improve the flow.
- Added an example and additional discussion to the Header Search Paths subsection for the interaction between generator expressions and the use of relative paths with
target_include_directories()
. - Added a
target_compile_definitions()
example to the Compiler Defines subsection. - Added an example to the Compiler Options section to highlight how some things can safely be set conditionally using
if()
logic, but others must use generator expressions. - Added a number of examples to the Directory Properties And Command section to highlight the different behavior of properties and commands regarding their effect depending on where they are set or called (before or after a target is created). An example was also added to show the usefulness of generator expressions for setting language-specific options with
add_compile_options()
. - The discussion of the
debug
,optimized
, andgeneral
keywords forlink_libraries()
in the Directory Properties And Command section was significantly reduced, and theDEBUG_CONFIGURATIONS
global property is no longer mentioned. These are very old features that projects should no longer need or use. - The System Header Search Paths subsection contains an example that uses
FetchContent
. Previous versions had a call toFetchContent_MakeAvailable()
with no argument. This has now been corrected to include the missinganotherdep
argument. - A paragraph was added to the Runtime Library Selection subsection for the new
VS_USE_DEBUG_LIBRARIES
target property andCMAKE_VS_USE_DEBUG_LIBRARIES
variable added in CMake 3.30.
Language Requirements chapter:
- The
<LANG>_STANDARD
part of the Setting The Language Standard Directly section was rewritten to use tables to show which CMake versions support which language versions. The previous editions had become hard to read as more standards and versions were added, and the new tables are much easier to digest at a glance. Details for the HIP language are now also included in the tables. - The Requirements For C++20 Modules section was updated to make clear that an error is generated in the consuming project rather than the exporting project if a
cxx_std_20
compile feature or higher isn’t set on an exported target.
Advanced Linking chapter:
- CMake 3.30 added some improvements around combinations of link features. A brief note was added about this to the Custom Features subsection.
Custom Tasks chapter:
- Added a brief paragraph to the end of the Commands That Generate Files section, mentioning the relevance of the
CMP0118
andCMP0163
policies for generated files.
Working With Files chapter:
- CMake 3.30 added support for a
TLS_VERSION
keyword forfile(UPLOAD)
andfile(DOWNLOAD)
, and an associatedCMAKE_TLS_VERIFY
environment variable and CMake variable. The Downloading And Uploading section has been updated accordingly.
Libraries chapter:
- The last paragraph in the Additional Complications With C++20 Modules subsection was updated to highlight that any files a module interface file depends on must also be installed, such as the
algo_export.h
header of the preceding example.
Toolchains And Cross Compiling chapter:
- Updated the Compiler Checks section to make clear that the
CMAKE_TRY_COMPILE_TARGET_TYPE
variable should only be set in a toolchain file, not by a project.
Build And Test Mode chapter:
- Updated examples to use
cmake -B build ...
instead of manually making and changing to thebuild
directory first.
Installing chapter:
- In the Runtime Dependency Sets subsection, the
install(RUNTIME_DEPENDENCY_SET)
example for Windows contained a robustness issue. ThePOST_EXCLUDE_REGEXES
regular expression assumed paths only contained forward slashes (/
). But CMake doesn’t guarantee this, and in fact sometimes it produces paths with mixed path separators. The example has been updated to handle both forward or backslashes as path separators. A paragraph was also added after the example to highlight this behavior.
Package Generators chapter:
- The default behavior of the
CPACK_WIX_INSTALL_SCOPE
variable was reverted late in the CMake 3.29 release series (3.29.5). The default was changed again in CMake 3.30, but only for the newly supported WIX 4 version. Issues were also found when updating packages installed with an oldercpack
version if the install scope was changed, requiring projects to manually alert their users to the problem. These things are now discussed at the end of the WIX section.
FetchContent chapter:
- In the opening paragraph, added 3.30 as one of the CMake versions with significant improvements for
FetchContent
. - The note at the end of the Basic Usage section was updated to highlight that the old manual population pattern is now officially deprecated as of CMake 3.30.
- A new Avoiding Sub-builds For Population section has been added. CMake 3.30 gained the ability to avoid using a separate sub-build to fetch each dependency. It can now use a much more efficient method that directly executes as part of the main project. Performance gains for large projects with many dependencies can be substantial for Windows and Xcode builds. The Recommended Practices section was also updated with a recommendation to use this new behavior.
- The Developer Overrides section was reordered slightly to improve the logical flow.
Presets chapter:
- CMake 3.30 added presets schema version 9. This has been added to the corresponding version table in the High Level Structure section.
Working With Qt chapter:
- Some Qt-provided translation commands for CMake have been in technology preview since early in the Qt 6 timeframe. Qt 6.7 made them official, but at the same time deprecated them in favour of better replacements. Examples throughout this chapter have been updated to use Qt 6.7 as their version for consistency with the newer APIs.
- The Translations section was substantially reworked to reflect the new form of the
qt_add_translations()
command, and the associated changes to theqt_standard_project_setup()
command. The old form is still discussed, but in less detail. - The Qt Deployment Tools subsection was updated to mention the new
DEPLOY_TOOL_OPTIONS
keyword forqt_generate_deploy_app_script()
, which was added in Qt 6.7. - The Deploying Translation Files subsection and the Recommended Practices section were also updated to reflect the new API added in Qt 6.7.