cmakecmake-presets

CMakePresets.json vs CMakeSettings.json vs CMakeLists.txt


I've googled around a bit but I've not found anything really satisfactory. There are a lot of tutorials on how to use them, but I'm struggling to understand which one best fits a particular project.

It's not very clear to me, for each of them, what should I use for. As far as I understood (and that might not be right), all of them overlap in some features, such as defining environment or CMake variables.

What I've generally understood is that CMakePresets and CMakeSettings are Microsoft tools (maybe tool is not the right word, but I couldn't come up with a better one) for integration of a CMake project in MS IDE (VS and VSCode). How they cope with CMakeLists and what are the scope of each one?


Solution

  • Every project needs to have a CMakeLists.txt file that configures the CMake project. You can learn more step-by-step by following the official CMake tutorial. Here's a tutorial on CMakeLists.txt files by CLion.

    CMakePresets.json is an optional, builtin CMake feature. It is not a Microsoft-specific thing. It's a tool to allow writing up presets for configuration, build, test, and packaging settings that are commonly used together. That's what it's useful for. Ex. filling in option() variables (that are defined in the project's CMakeLists.txt file), or other cache and environment variables. Presets are basically a tool to not have to write many commonly-used-together commandline arguments for common user scenarios and instead have a shortcut/alias for them.

    CMakeSettings.json is specific to Visual Studio. You can use it when building projects specifically with Visual Studio. It has some similar capabilities as CMakePresets.json files, but is much more oriented to work with Visual Studio IDE configuration. The official docs recommend that it no longer be used, and that CMakePresets.json be used instead.


    Here's an analogy for what presets are and when they're useful: Imagine a project is like a sandwich shop where you pick what ingredients you want in the sandwich (what options you want to choose when configuring the project build). Let's say one sandwich shop has (among many other ingredients), bacon, lettuce, tomato, and cucumber, which are the ingredients you like to have in your sandwich. The list of all the possible ingredients to choose from is the CMakeLists.txt file. The shop notices that many people like to order sandwiches with bacon, lettuce, and tomato together, so they make a preset: "B.L.T.". So now, you can tell them what you want faster: Instead of bacon, lettuce, tomato, and cucumber, you can say: "I want a B.L.T. with cucumbers" (Ex. cmake --preset=BLT -DWITH_CUCUMBERS=YES ...). Now imagine a different shop with many more ingredients, and you often ordering the same thing with many more ingredients. Can you see how that would be useful? Now- not all customers will commonly want the same thing, and the "official" presets are determined by the shop owner (the project maintainers commit a CMakePresets.json file to their project repo), but you might want to have some custom presets. That's what the CMakeUserPresets.json file is for (never committed to project repo. In .gitignore).

    So how do you choose what settings to put in the CMakeLists.txt versus a CMakePresets.json if you choose to create one? If you are 100% certain that one specific value for something (a CMake variable, an environment variable, etc.) will always be the desired value to be used and nobody will want anything different, then hardcode it in the CMakeLists.txt (Ex. target_compile_features, when a target's interface or internal sources require a specific language version to use / build). Otherwise, use the appropriate mechanism (Ex. set(... CACHE ...), option(), if(DEFINED ...)) to define the setting with an overridable default value in the CMakeLists.txt and leave the choice up to the user at configuration time, and if useful, provide some preset bits to help them / yourself out.

    More examples: Here are some things that I generally wouldn't hardcode in a CMakeLists.txt file, but I would put in certain presets: CMAKE_CONFIGURATION_TYPES, CMAKE_EXPORT_COMPILE_COMMANDS, CMAKE_COLOR_DIAGNOSTICS, CMAKE_DEFAULT_BUILD_TYPE- at least- not except within an if(NOT DEFINED ...) block.