CMake Anti-Antipatterns

Cheat sheet for modern CMake, ignoring the old way.

Why Anti-Antipatterns?

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():


This will translate the feature into the flag that is appropriate for the compiler. These are complete lists of C features and C++ features.

Set Include Flags

To add -I or -isystem flags, use target_include_directories():


This will pass -Ipath/to/directory to the preprocessor.

Set Compile Definitions

To add -D flags, use target_compile_definitions():


This will pass -DOPTION to the preprocessor. There is no need to add -D yourself.

Set Compile Options

To pass other compiler flags, use target_compile_options():


For example,

    PRIVATE -Wall

will pass -Wall to the compiler.

To link against a library, use target_link_libraries():


If possible, specify the library using an alias target (using a ::). 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. Explanation here.