I am working through Professional CMake and section 5.5 - Potentially Surprising Behaviour of Variables discourages accessing cache variables using $CACHE{variable}
except when debugging. The exact quote is:
Projects should not generally make use of this other than for temporary debugging, since it breaks the long-established expectation that normal variables will override values set in the cache.
I did not understand this reasoning so I created two examples. The first uses $CACHE{variable}
and the second avoids it by unsetting the normal variable that is shadowing the cache variable.
Approach 1:
cmake_minimum_required(VERSION 3.27)
project(example)
set(variable "Hello" CACHE STRING "An example variable" FORCE)
set(variable "Goodbye")
message("The normal variable's value is ${variable}.")
message("The cache variable's value is $CACHE{variable}.")
Approach 2:
cmake_minimum_required(VERSION 3.27)
project(example)
set(variable "Hello" CACHE STRING "An example variable" FORCE)
set(variable "Goodbye")
message("The normal variable's value is ${variable}.")
unset(variable)
message("The cache variable's value is ${variable}.")
Both produce the expected output of:
The normal variable's value is Goodbye.
The cache variable's value is Hello.
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: ...
It therefore seems that $CACHE{variable}
is better at showing the author's intention than ${variable}
and while it does break "long-established expectation", I struggle to see how someone could get confused by this.
I could not find anything on Google and I looked at the CMake documentation for the latest version (3.27) but it did not mention whether it should be used or not.
At the moment, I prefer the simplicity and conciseness of $CACHE{variable}
and want to know, beyond breaking "long-established expectation", if there is any reason why I should not use $CACHE{variable}
to access all the cache variables in CMakeLists.txt
?
I'm just going to expand on what 273K said in the comments, because while I agree it's "so easy" to follow the manual, I also think it's valid (and important) to understand why the manual recommends what it does.
Assume you're building a library:
...
add_library(foolib STATIC ...)
target_compile_definitions(foolib PRIVATE "${foolib_special_behavior}")
...
Where foolib_special_behavior
is a variable that's usually set in the cache.
Now someone is trying to use your library as a dependency in another project:
...
set(foolib_special_behavior "SPECIAL")
add_subdirectory("dependencies/foolib")
...
This is a usual pattern when including something as a subdirectory: you set any configuration options you want to use before including the subdirectory.
Now if you had used target_compile_definitions(foolib PRIVATE "$CACHE{foolib_special_behavior}")
, this would not work - the project embedding you would have to set variables in the cache.