c++cmakecmake-language

What reasons are there to discourage accessing CMake cache variables using `$CACHE{variable}`?


Problem

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.

Question

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?


Solution

  • 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.