Using CMake Presets to Standardize Configure and Build Invocations
Learn how to commit CMakePresets.json for reproducible builds while keeping user‑specific settings separate, with a worked example and verification steps.
22 Aug 2025, 00:54 UTC

The problem: ad‑hoc cmake commands drift across machines
When developers invoke cmake manually with different generators, toolchain files, or cache variables, the resulting build trees can diverge. CI pipelines often rely on wrapper scripts that duplicate logic, making it hard to guarantee that a local build matches what runs in the pipeline.
Thesis: commit CMakePresets.json, keep user overrides in CMakeUserPresets.json
CMake Presets (available since CMake 3.19) let you declare configure and build settings in JSON. By storing CMakePresets.json in version control and adding CMakeUserPresets.json to .gitignore, you separate shared defaults from personal paths while preserving reproducibility.
How presets work
A configure preset records the generator, toolchain file, cache variables, and include directories needed for cmake --preset <name>. A build preset pairs with a configure preset to define the build type, parallelism, and target set for cmake --build --preset <name>. Both files use a JSON schema that CMake validates at configure time.
Worked example: a Linux GCC project
Suppose the project needs a debug build with GCC, installing to a local _install folder. The shared preset file might look like this:
{
"version": 3,
"configurePresets": [
{
"name": "linux-gcc",
"displayName": "Linux GCC Debug",
"generator": "Ninja",
"toolchainFile": "${sourceDir}/toolchains/gcc.cmake",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "DEBUG",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/_install"
}
}
],
"buildPresets": [
{
"name": "linux-gcc-debug",
"displayName": "Build Linux GCC Debug",
"configurePreset": "linux-gcc",
"jobs": 4
}
]
}
Each developer can create a local CMakeUserPresets.json to override, for example, the install prefix without touching the shared file:
{
"version": 3,
"configurePresets": [
{
"name": "linux-gcc",
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "/home/alice/local/install"
}
}
]
}
Running the build locally now mirrors CI:
cmake --preset linux-gcc -S . -B build(or simplycmake --preset linux-gccif the source and build trees are set)cmake --build --preset linux-gcc-debug
Verification steps
To confirm that the presets are correct and that the team is using the same settings:
- List presets:
cmake --list-presetsshould show bothlinux-gccandlinux-gcc-debug. - Inspect effective cache:
cmake --preset linux-gcc -LAHprints cache variables; verify thatCMAKE_BUILD_TYPEisDEBUGand the install prefix matches expectations. - Compare build output: Run
cmake --build --preset linux-gcc-debug --verboseand compare the compiler invocations and output directory layout with the CI logs.
Trade‑offs and limitations
Presets are version‑sensitive; the basic schema requires CMake 3.19, while fields like includeDirectory appeared in later releases. Document the minimum CMake version in your README. Mixing presets with manual -D flags or legacy wrapper scripts can cause duplicate or conflicting cache entries because presets already apply those values at configure time. JSON syntax errors are reported only at configure time, which can block the whole team; a quick cmake --list-presets after editing catches most mistakes.
Actionable closing
Add CMakePresets.json to your repository, add CMakeUserPresets.json to .gitignore, and document the required CMake version. Encourage developers to use cmake --preset <name> for configuration and cmake --build --preset <name> for builds. Periodically run the verification steps above to ensure that local and CI builds stay in sync.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.