CMake Presets

Learn the fundamentals of CMake Presets. This lesson introduces CMakePresets.json to simplify complex build commands.

Greg Filak
Published

Throughout the last few chapters, our build commands have been getting progressively more complex. We've added toolchain files for package managers, specified build types, and configured cross-compilation.

This has led to a new problem: our command-line invocations have become long, hard to remember, and difficult to share with others using our project who may find them useful.

This is where CMake Presets come in. Presets are a modern, standardized way to define and share common build configurations in a simple JSON file. They allow you to replace a long, error-prone command with a single, memorable name.

In this lesson, we'll learn the fundamentals of presets. We'll start by encapsulating a complex command into our first configure preset, then add a corresponding build preset, and finally understand the distinction between shared team presets and personal user presets.

In these examples, we'll use our vcpkg project from the previous chapter. The code is provided below if you want to follow along. Note that the include() command in the toolchain file (highlighted) may need updated to point to your vcpkg location. We'll learn how to make this portable soon.

Files

CMakeLists.txt
vcpkg.json
toolchains
app
Select a file to view its content

Preset Version Requirements

Support for presets were first introduced in version 3.19 of CMake, and were expanded in subsequent versions. Later in the chapter, we'll use features added in 3.21 so, if you want to follow along, having at least that version is recommended.

Remember, you can check the installed cmake version using the command:

cmake --version

Using a recent addition to the cmake executable doesn't necessarily require us to update the cmake_minimum_requirements() for our project. Someone on an older version could still use our project without using our presets.

However, if our project is designed around the use of presets, and our documentation recommends using them, bumping the cmake_minimum_required() version is a reasonable choice anyway. This signals to users that a more modern version of CMake is expected in order to use the project as designed.

CMakeLists.txt

cmake_minimum_required(VERSION 3.21) 
project(Greeter)

// ...

The Command-Line Chore

Let's revisit the command we used to cross-compile our Greeter application for Windows from a macOS or Linux host. It required setting the source and build directories, the toolchain file, and the build type.

For example, if our terminal was in our project root, and we wanted to configure a vcpkg project in /build/windows-debug, our command to provide all of the required arguments might look like this:

cmake -S . -B ./build/windows-debug \                      
  -DCMAKE_TOOLCHAIN_FILE=./toolchains/mingw-windows-x64.cmake \
  -DCMAKE_BUILD_TYPE=Debug

And after that, we still need to repeat the correct build directory for the build command:

cmake --build ./build/windows-debug

This is a lot to type correctly every time. If a new developer joins the team, you have to document this command precisely. If you need to change a flag, you have to tell everyone to update their personal scripts.

Creating a Configure Preset

CMakePresets.json is the solution. It's a file you create in the root of your project that lets you give names to these complex configurations.

Let's create this file and define our first preset to encapsulate the command above.

CMakePresets.json

{
  "version": 3,
  "configurePresets": [{
    "name": "windows-x64-debug",
    "displayName": "Windows x64 Debug",
    "description": "Build for 64-bit Windows with MinGW (Debug)",
    "binaryDir": "${sourceDir}/build/windows-x64-debug",
    "cacheVariables": {
      "CMAKE_BUILD_TYPE": "Debug",
      "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/toolchains/mingw-windows-x64.cmake"
    }
  }]
}

Let's break down this JSON file:

  • "version": The schema version for the presets file. CMake adds support for new keys and features in presets over time. Version 3 is a relatively common baseline and is supported by CMake versions 3.21 and later.
  • "configurePresets": An array containing one or more configure preset objects.
  • "name": The unique, machine-readable ID for the preset. This is what you'll use on the command line to declare that you want to use this preset. It's best to use a simple, consistent naming scheme like os-arch-config.
  • "displayName" and "description": Human-readable strings that GUI tools such as an IDE can use to present the preset in a friendly way.
  • "binaryDir": The output directory for the build. This corresponds to the -B argument we'd pass on the command line. The ${sourceDir} variable is automatically provided by CMake and points to the directory containing the CMakePresets.json file.
  • "cacheVariables": An object containing key-value pairs that will be passed as -D arguments to the cmake command. This is where we can set things like CMAKE_BUILD_TYPE and CMAKE_TOOLCHAIN_FILE.

Listing Presets

We can ask CMake to list all of the available presets using the following command:

cmake --list-presets

The output should list our new preset as an option:

Available configure presets:
  "windows-x64-debug" - Windows x64 Debug

Using Presets

With this file in our project root, our long, complex configure command is now replaced with a simple, memorable one:

cmake --preset=windows-x64-debug

CMake will read CMakePresets.json, find the preset named "windows-x64-debug", and apply all the settings defined within it.

With that one command, we should now see our project configured in the /build/windows-x64-debug directory, just like our preset requested.

Overriding Preset Values

If a preset isn't defined exactly how we want, we can still override its settings on the command line.

For example, we could use all the preset values, but override the preset-defined binaryDir of /build/windows-x64-debug to instead use ./output:

cmake --preset=windows-x64-debug -B "./output"

CMake allows us to save personal preferences like this in a CMakeUserPresets.json file, which doesn't interfere with the configurations shared among the wider team in the CMakePresets.json file. We cover user presets in the next lesson.

Adding Build Presets

Simplifying the configure step is great, but we can create presets for the build step too. This lets us create a complete, named workflow from start to finish.

Let's add a buildPresets section to our file:

CMakePresets.json

{
  "version": 3,
  "configurePresets": [{
    "name": "windows-x64-debug",
    "displayName": "Windows x64 Debug",
    "description": "Build for 64-bit Windows with MinGW (Debug)",
    "binaryDir": "${sourceDir}/build/windows-x64-debug",
    "cacheVariables": {
      "CMAKE_BUILD_TYPE": "Debug",
      "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/toolchains/mingw-windows-x64.cmake"
    }
  }],
  "buildPresets": [{
    "name": "windows-x64-debug",
    "displayName": "Build Windows x64 (Debug)",
    "configurePreset": "windows-x64-debug"
  }]
}

In this example, our three values are:

  • "name": The name of the build preset, which we'll use to identify it on the command line. It's a common convention to give the build preset the same name as the configure preset it's associated with.
  • "displayName": As with configure presets, we can give our build presets a friendly name that can be displayed on GUI tools.
  • "configurePreset": This is the crucial key. It links this build preset to a specific configure preset. When you use this build preset, CMake knows it corresponds to the configuration done by windows-x64-debug.

Now, we can also complete the build step from the project root, using our named preset:

cmake --build --preset=windows-x64-debug

In this case, the build preset isn't quite as useful as the configure preset. The only benefit is that we no longer need to provide the build directory (./build/windows-x64-debug) because that was already set in the configurePreset that our build preset links to.

However, as we'll see later, the commands needed to execute build steps can also get quite complex. But with our new knowledge of build presets, rather than those commands needing to be typed, we can just add the options to our CMakePresets.json collection, making them easier to use and share.

Summary

CMake Presets are a feature that improves the usability of the CMake command line, turning complex, error-prone commands into simple, named workflows.

  • The Problem: Long cmake command lines with many arguments are hard to remember, type, and share.
  • The Solution: Define configurations in a CMakePresets.json file.
  • Configure Presets: Define values like the generator, build directory, and cache variables for the cmake command.
  • Build Presets: Link to a configure preset to define a corresponding workflow for the cmake --build command.
Have a question about this lesson?
Answers are generated by AI models and may not be accurate