Lesson 11 · Targets: the core model
Compiler flags and warnings
Add flags per target with target_compile_options. Enable warnings the documented way, per compiler, without touching third-party code.
Your code should compile with warnings enabled, but only for your code, and with flags that exist on the compiler you are using. This lesson shows the per-target way to do it.
The per-target command
target_compile_options(app PRIVATE -Wall -Wextra)
Same grammar as everything else. Attach to one target, PRIVATE so it does not leak into libraries you link.
Why
add_compile_options(-Wall)is global. It would also apply to everyadd_subdirectorytarget you do not own, including third-party code whose warnings you cannot fix. Per-target options mean your warnings, your code.
Flags are compiler-specific
-Wall is GCC and Clang. MSVC wants /W4. Writing one line that works everywhere means branching on the compiler. The official tutorial shows the pattern, checking the frontend variant, which also catches clang-cl, since it uses the MSVC frontend:
if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "MSVC")
target_compile_options(app PRIVATE /W4)
elseif(CMAKE_CXX_COMPILER_FRONTEND_VARIANT MATCHES "GNU|Clang")
target_compile_options(app PRIVATE -Wall -Wextra)
endif()
Tip
Wrap it in an interface library (lesson 13) so every target in your project gets the same warnings with
target_link_libraries(app PRIVATE warnings). That is the pattern larger projects use instead of repeating theifblock.
Warnings as errors. Do not default to it
Turning warnings into errors (-Werror / /WX) makes CI fail on any warning, which sounds great. But it breaks the moment a new compiler version adds a warning to your dependencies’ headers. The docs are explicit. Projects should not turn warnings-as-errors flags on by default.
# OK for your own code, as an opt-in for CI. Not the default.
option(APP_ENABLE_WERROR "Treat warnings as errors" OFF)
if(APP_ENABLE_WERROR)
if(MSVC)
target_compile_options(app PRIVATE /WX)
else()
target_compile_options(app PRIVATE -Werror)
endif()
endif()
Definitions
-DFOO=bar has a per-target form too:
target_compile_definitions(app PRIVATE VERSION=2 NDEBUG)
The old global add_definitions(-DVERSION=2) is the same reasoning as before. Attached to a target, it cannot leak.
Note
CMake itself leaves MSVC-style warning flags out of
CMAKE_<LANG>_FLAGSby default (policy CMP0092, NEW since 3.15), precisely so that you decide per-target. If you see a tutorial settingCMAKE_CXX_FLAGS "-Wall", that is the old style.
Pitfall
Do not put compiler flags in
CMAKE_CXX_FLAGSfor your project. It is global, it affects every target, it persists in the build directory’s cache even after you delete the line, and it breaks the one-target-one-requirement model. Flags belong on targets.
Read the docs