Lesson 16 · Organize your project
Options and cache variables
Make your build configurable with option() and cache variables. How cmake -D works, why first-set-wins, and cmake-gui.
Not every build is the same. Sometimes you want tests, sometimes not. Sometimes debug, sometimes release. Options and cache variables are how a project exposes switches to the person running CMake.
option(), the simple switch
option(MYAPP_BUILD_TESTS "Build the test suite" ON)
- The first argument is the variable name. By convention
PROJECTNAME_SOMETHING, prefixed so it never collides with other projects. - The second is the help text shown in
cmake-guiandccmake. - The third is the default,
ONorOFF.
Use it:
if(MYAPP_BUILD_TESTS)
add_subdirectory(tests)
endif()
The person configuring can flip it:
cmake -S . -B build -DMYAPP_BUILD_TESTS=OFF
Cache variables, options with a value
An option() is really a cache variable of type BOOL. The general form covers everything else:
set(MYAPP_LOG_LEVEL "info" CACHE STRING "Log verbosity: debug | info | warn | error")
Cache variables have two properties that normal variables do not:
- They persist. Stored in
build/CMakeCache.txt, remembered across configurations. - First set wins. Once the cache holds a value, from
-Dor a previous run, laterset(... CACHE ...)calls do not overwrite it. They only set it if it is missing.
Why
“First set wins” is what makes
-Dwork. Your command-line value is written to the cache once, and every later configure respects it, even when a third-partyCMakeLists.txttries to set the same variable with its own default. The cache is the user’s voice, and it outranks project defaults. Configure once, forget.
Pitfall
To change a cached value, pass
-Dagain,cmake -S . -B build -DMYAPP_LOG_LEVEL=debug, or delete the entry from the cache. Editing theset(... CACHE ...)default in yourCMakeLists.txthas no effect on an existing build directory. The old value is still cached. Fresh build dirs pick up new defaults.
The cache variable everyone uses, build type
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
CMAKE_BUILD_TYPE selects debug or release flags. For single-config generators (Ninja, Make) it is set at configure time. For multi-config generators (Visual Studio, Ninja Multi-Config) you pick per build with --config (lesson 21). A good default in your project:
# Sensible default. Users can override with -D.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()
Note
FORCEhere is the rare, deliberate exception to first-set-wins. It sets the default when nobody chose anything, without overriding an explicit-D. The guard checks it is a single-config generator, so multi-config builds, which use--configinstead, are left alone.
cmake-gui, the visual cache editor
cmake-gui .
It shows every cache variable with its help text, lets you flip options, and reconfigures with one click. Useful when you inherit a project and want to see what is configurable. The help text from option() and set(... CACHE ...) is exactly what you will see.
Tip
Give every cache variable a clear help string. It is user documentation.
set(MYAPP_MAX_CONN 10 CACHE STRING "Maximum simultaneous connections")beats an empty string for everyone who runscmake-guion your project.
Read the docs