in CMakePresets.json I can define the values of cmake cache variables.
I was assuming that the values I set there are “only” presets, i.e. the values used when initially running cmake. For that I provided some configure-presets which set some variables to useful default values for a certain group of developers in my project.
I was assuming that it will still be possible to use cmake-gui to change the value of these variables afterwards (since the presets are “only” pre-sets I thought).
But, when using VS Code, this doesn’t work. I am not able anymore to change cache variables via cmake-gui which are defined in a preset. Whenever VS Code decides that cmake must run again, the presets are applied again, discarding the changes I did to the cache variables.
Is this how the presets should be used by IDEs ?
It’s a bit unfortunate, since developers now have to learn that changing the options of a cmake-based project via cmake-gui may be overridden by some other mechanism, the presets json file.
This is slightly related to “presets: combinatorial explosion” (https://gitlab.kitware.com/cmake/cmake/-/issues/22538), since my solution was to the issue was to create an additional set of presets, with those variables set differently. :-/
Getting slightly off-topic: I don’t understand why e.g. VS Code and VS basically require CMakePresets. For a not-total-beginner cmake user it is not hard to create a build tree, and I think users have learned how to use e.g. cmake-gui over the years. It would be so easy for IDEs to just keep that working, and adding the possibility to “load” an (any) existing cmake build tree, by simply putting a file API query file in the build tree and read all necessary information from the response files. If the reply file exists already in the build tree, they could simply read it and be done, instead of forcing a cmake rerun (which can actually take some time under Windows). This would be so easy, and I would still be able to create any number of custom build trees for my projects and use them in VS Code. Instead they force users to add a preset for every build tree (as far as I can see).
Btw. I created a ticket for VS Code early last year, in case you want to support this idea: Create configure- and build-presets on-the-fly from an existing build tree · Issue #4293 · microsoft/vscode-cmake-tools · GitHub
When I tried to use VS Code with source code in WSL, it also worked without presets. But it does only offer that if no preset files is present…rather dumb if you ask me. That’s why I currently prefer wrapper scripts instead.
IMHO presets should only apply on the (re-)creation of a build tree. What does CMake do internally when changing a cmake file and starting a build?
When simply building (by calling make/ninja/cmake –build), or when simply rerunning cmake (e.g. by cmake . or make rebuild_cache) it does not reapply the variable values from the presets. When rerunning cmake with --preset foo , it does reapply the variable values from the presets.
When developing, I think the only reason to run cmake with the –preset option might be to reapply the variable, but actually I think developers normally wouldn’t do it.
Any comments from the main CMake developers ?
(I don’t want to create a ticket at VS Code which says “apply the presets only on the initial run” if reapplying the presets everytime is maybe indeed how it is supposed to be done)
Reapplying the presets is not typical usage AFAIK. --preset foo is approximately equivalent to spelling out all the preset’s settings via explicit command-line flags. In command-line cmake workflows one typically doesn’t reconfigure an existing build tree by spelling out all the explicit cache entries used the first time. Therefore one typically shouldn’t reconfigure with an explicit --preset foo again except to intentionally reset things.
As a counter-point, an IDE cannot know whether the user has done something outside the IDE since the last time the IDE invoked cmake for configuring the build. It can’t even assume the build directory is still in a valid, configured state. To be conservative, the IDE has to provide the full set of preset options. I believe this is what all the major IDEs are doing, and I’d personally be more annoyed if they didn’t do that. I frequently re-run CMake configure from my IDE and expect it to reapply the preset settings.
If a CMakeCache.txt exists, it should be enough to just run cmake . , no ?
If also a query and a reply file exist, it would have to be quite special circumstances so that the reply-file would be out of date, no ?
The cache variables should be only different if the user intentionally changed them, and then the IDE should not discard that, IMO.
If I may add an external opinion to the discussion FWIW, from having tinkered with CMakePresets.json on some projects, they seem to be designed and work more as a contract between the project and the consumer: “Building the project using one of the following presets is extra robust compared to providing your own configuration.”
Presets feel like the ideal candidates for CI and testing. By incorporating them with the above mindset, they will generally not accomodate you, but they will mostly always do the same thing for everyone unless you e.g. mess with the CMakeCache.txt a posteriori or rely on environment variables for configuration.
There’s some well-known names in the discussion, so let me know if there’s any flaw in my understanding!
For me, presets only work within the narrow path of toolchains that come with the system or are tightly integrated with it.
I have not found a way to use it with my old Boot2Qt Yocto toolchain that even relies on an environment for its toolchain file. Same for any VS toolchain on command line.
At any point, it can get so complex that the means available for preset definitions are not sufficient. Some IDEs can work around this for some kind of toolchains (like QtCreator for Boot2Qt) and others don’t (VS Code here). Solely relying on presets gives you an incomplete solution, then. The contract that you describe is only complete with documentation or scripts for the surrounding part.
For me, this only moves some parts from a scripts to a preset. If this is a gain is up for each project to decide.
Back to the topic: I would never overwrite the changes a user did to cmake variables. Thus, cmake should only apply a preset when starting in a fresh build tree.
Consider this scenario (which I see with my consulting clients all the time). A project defines a set of presets in its CMakePresets.json file so that all developers can have a reliable set of build configurations. After a while, a preset needs to change a value of a cache variable. Developers update to pick up the change. The next CMake configure will apply that change and the developer gets the updated configuration applied. This is robust, requires no “hey everyone, delete or manually update your CMakeCache.txt” announcement that all developers would have to see and remember at the point in time where they update to that commit (could be months later).
Presets as currently implemented robustly and inherently handle scenarios like the one described above. As @AnthonyD973 commented, they capture a contract between the project and the consumer: If you use this preset, you’ll get a build configured exactly how the preset describes. We don’t require (nor should we, in my view) that developers have to know to do a fresh reconfigure if anything about a preset changes.
Indeed, they have turned out to be good for those, and I also use them like that in production projects. However, the original use case they were created for was for IDEs. They’ve grown well beyond that now, and that’s fine (I welcome it!), but we do have to ensure that presets continue to support the purpose that originally motivated their creation.
Yes, it would. But what if the preset changes? Either the IDE has to track the full details of the preset it last configured with and re-run an enforced configure if anything changes (which would discard any changes the user made outside the IDE), or the IDE would have to tell the user “Hey the preset changed, do you want to discard the current configuration and apply the new one?”. I doubt IDEs would be keen to implement the latter.
I tried a bit, I can work around the current behavior with some cmake scripting:
function(option_with_preset name msg, default)
set(def_value “${default}”)
if(DEFINED ${name}_PRESET)
set(def_value “${${name}_PRESET}”)
endif()
option(${name} “${msg}” “${def_value}”)
endfunction()
option_with_preset(ENABLE_SOME_FEATURE “Enable some feature” TRUE)
and in the presets file set “ENABLE_SOME_FEATURE_PRESET”: “TRUE”.
This will initialize the cache variable with the value from the preset, and then be independent from it. With a bit more scripting the opposite behaviour should work too ( if the preset value changes, force the cache value).
In a shell environemtn, if the preset changed, nothing happens until a configure call with that explicit preset is made, or a configure call is done cause of a deleted cache (or build directory). Just changing the preset (-file) on disk does nothing. A IDE can (and should?) trigger –preset by explicit selecting a preset. Nowadays every IDE/editor (at least the ones I know, and at least the one supporting cmake presets) are watching at least the opened files, and warns you if there is a change on the filesystem. Asking to reconfigure if the actual used preset file is chanded shouldn’t be such a problem. Adding a initial time-stamp compare on startup (or a forced reconfigure with the last preset) shouldn’t be a problem either.
If I do apply the preset on every configure, do we need the cmake cache any longer? It is no longer a “preset”, but a complete “set”, cause. How long is a changed in the cache valid? Per design the cache is the central point of information. For a strict enforcement even $ENV{} access might produce warnings when not used to initialize/update the cache.
Shell and IDE behavior should be the same. Otherwise I can not used them (or several IDEs/editors) together in a mix mode.
That’s very nicely put. As you said, this changes the meaning of the CMakeCache.txt, of recommendations how to change builds settings - it has to be done via the presets, not the cache anymore.
As a workaround I have now settled on putting just MYVAR_INIT variables in the preset, and use their value, if it exists, as default value for the actual cache variable MYVAR (wrapped in a function).