Rather than using the command line and the -D flag to set variables, I've been using set() inside the CMakeLists.txt for my simple "learner" one-directory project. The advantage is not having to remember and/or copy and paste long directory names every time I call cmake -DVARIABLE_NAME=path/to/infinity/and/beyond ..
My question is what is the functional difference between the two methods, and what are some simple use cases where I might not want to use set instead of the command line -D flag?
This answer talks about scope of variables in cmake, and may contain the answer to my question, but it is too convoluted for me to follow: What's the CMake syntax to set and use variables?
This answer provides a use case where the two methods are not the same, but is for some specific variable and library I have no knowledge of so can't relate to: Setting "-D" variables inside CMake
Note: My question does not have a specific context but was inspired by following this pytorch tutorial to setup my first C++ project and use pytorch.
-D sets variables as cache variables (see also Mastering CMake chapter, and variables docs), which means that even though they aren't set in the configuration files, they will be remembered. You can optionally specify a type. If you set the type to PATH or FILEPATH, the value will be converted to an absolute path.
set sets variables. You can pass CACHE to set the variable as a cache variable. You can also set the type using the TYPE argument. Non-cache variables are scoped to blocks, functions, and directory scopes (docs). You can specify a type, and also a docstring.
Both cache and non-cache variables can be referenced using the same syntax (docs and related nuance: policy CMP0126).
Generally speaking, if the variable is something that you think someone building your project might want to have control over, then you should leave it to the user to use -D, and set a "default value" in your CMakeLists.txt by using set(... CACHE ...). Note that for potentially non-cache variables, you can do similar using if(DEFINED ...) to conditionally only set the variable hasn't been set yet. I've written about this also in my answer to "CMakePresets.json vs CMakeSettings.json vs CMakeLists.txt". If the variable is a boolean, there's a shorthand command for defining a cache variable: option.
The advantage is not having to remember and/or copy and paste long directory names every time I call cmake [...]
Note that most shells have history functionality, so you can recall past commands you've executed. Actually, CMake's Preset feature sounds right up your alley. You can create a user-local CMakeUserPresets.json file (put it in your .gitignore) suited exactly for your personal needs. Note that if you are calling CMake to reconfigure and regenerate an already configured and generated buildsystem for the purposes of changing cache variables, there are several tools which can make that easier for you as well, including the bundled interactive dialogs, cmake-gui and ccmake.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With