Cheat sheet for modern CMake, ignoring the old way.
As with many tools, CMake has evolved over time. Adoption of new techniques is not universal, so there are still many tutorials and products using “the old way” - antipatterns.
This is a select list of “the new way” - modern practices (not antipatterns). The antipatterns themselves are omitted; why add noise to the signal?
CMake Best Practices
In general, operate on targets. This keeps effects localized - settings for one target won’t unexpectedly bleed over to others.
Set Compiler Features
To specify compiler attributes (such as the language standard), use target_compile_features():
target_compile_features(TARGET [PUBLIC/PRIVATE/INTERFACE] <feature> )
Set Include Flags
-isystem flags, use target_include_directories():
target_include_directories(TARGET [PUBLIC/PRIVATE/INTERFACE] "path/to/directory" )
This will pass
-Ipath/to/directory to the preprocessor.
Set Compile Definitions
-D flags, use
target_compile_definitions(TARGET [PUBLIC/PRIVATE/INTERFACE] OPTION )
This will pass
-DOPTION to the preprocessor. There is no need to add
Set Compile Options
To pass other compiler flags, use target_compile_options():
target_compile_options(TARGET [PUBLIC/PRIVATE/INTERFACE] <flag> )
target_compile_options(TARGET PRIVATE -Wall )
-Wall to the compiler.
To link against a library, use target_link_libraries():
target_link_libraries(TARGET [PUBLIC/PRIVATE/INTERFACE] <library::library> )
If possible, specify the library using an
This allows CMake to throw a descriptive error while it is generating the build
system rather than waiting for the compiler to throw an error at link time.