Lesson 20 · Build & ship
Presets
Replace the configure and build incantation with cmake --preset. The CMakePresets.json format, configure, build, test and workflow presets.
Every project has a right way to configure it, and most projects only document it in a README that goes stale. Presets encode the right way in the project, so everyone, you, teammates, CI, IDEs, runs the exact same commands.
The problem presets solve
# What you type today, from memory, hoping it is right.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DMYAPP_BUILD_TESTS=ON -G Ninja
cmake --build build -j 8
# What presets give you.
cmake --preset release
cmake --build --preset release
Why
Presets are the project’s official instructions, machine-readable and committed to git. CI uses the same file as your laptop. No more “works with my flags” divergence. This is why every major project ships
CMakePresets.jsontoday.
The file
CMakePresets.json{ "version": 12, "cmakeMinimumRequired": { "major": 4, "minor": 4 }, "configurePresets": [ { "name": "dev", "displayName": "Dev (Ninja, Debug)", "generator": "Ninja", "binaryDir": "${sourceDir}/build/dev", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "MYAPP_BUILD_TESTS": "ON" } }, { "name": "release", "displayName": "Release", "generator": "Ninja", "binaryDir": "${sourceDir}/build/release", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } } ], "buildPresets": [ { "name": "dev", "configurePreset": "dev" }, { "name": "release", "configurePreset": "release" } ], "testPresets": [ { "name": "dev", "configurePreset": "dev", "output": { "outputOnFailure": true } } ], "workflowPresets": [ { "name": "dev", "steps": [ { "type": "configure", "name": "dev" }, { "type": "build", "name": "dev" }, { "type": "test", "name": "dev" } ] } ] }
Now the whole cycle is two words:
cmake --workflow --preset dev
One command. Configure, build, test, using the project’s own definition.
The preset kinds
| Preset type | Used by |
|---|---|
configurePresets | cmake --preset <name> |
buildPresets | cmake --build --preset <name> |
testPresets | ctest --preset <name> (lesson 25) |
packagePresets | cpack --preset <name> (lesson 24) |
workflowPresets | cmake --workflow --preset <name>, a sequence of the above |
One rule for workflows. The first step must be a configure preset, and every later step must reference that same configure preset.
Hygiene rules
CMakePresets.json. Commit it. It is the project’s contract.CMakeUserPresets.json. Do not commit it. Gitignore it. It is for personal overrides, your machine’s toolchain, your paths.- Presets can inherit from each other and be marked
hidden. The classic shape is a shared base plus small variants:
{
"name": "base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}"
},
{ "name": "dev", "inherits": "base", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } },
{ "name": "release", "inherits": "base", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } }
conditionslet a preset apply only on certain platforms or OS. For example, a Windows-only preset that exists only there.
Note
The preset format is a versioned JSON schema. It is a stable, supported format. Current schema version 12 maps to CMake 4.4. Each
versionnumber corresponds to a CMake release, so you can require a specific one viacmakeMinimumRequired.
Tip
cmake --list-presetsshows what is available. The fastest way to orient yourself in any repository. IDEs (VS Code, CLion, Visual Studio) read presets too, so the one-command story extends to one-IDE-config.
Pitfall
Do not hardcode machine paths, like
/home/you/..., inside presets. Use${sourceDir},${presetName}, or environment variables via theenvironmentfield. Presets are shared with CI and teammates.
Read the docs