3.6.2. Cache variables

Cache variables saved in CMakeCache.txt file:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(abc "687" CACHE STRING "")
[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hcache-cmakecachetxt -B_builds
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds
[usage-of-variables]> grep abc _builds/CMakeCache.txt
abc:STRING=687

3.6.2.1. No scope

Unlike regular variables CMake cache variables have no scope and are set globally:

# Top level CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

add_subdirectory(boo)

message("A: ${A}")
# CMakeLists.txt from 'boo' directory

set(A "123" CACHE STRING "")
[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hcache-no-scope -B_builds
A: 123
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

3.6.2.2. Double set

If variable is already in cache then command set(... CACHE ...) will have no effect - old variable will be used still:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(abc "123" CACHE STRING "")
message("Variable from cache: ${abc}")
[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cp double-set/1/CMakeLists.txt double-set/
[usage-of-variables]> cmake -Hdouble-set -B_builds
Variable from cache: 123
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds
[usage-of-variables]> grep abc _builds/CMakeCache.txt
abc:STRING=123

Update CMakeLists.txt (don’t remove cache!):

--- /examples/usage-of-variables/double-set/1/CMakeLists.txt
+++ /examples/usage-of-variables/double-set/2/CMakeLists.txt
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 2.8)
 project(foo NONE)
 
-set(abc "123" CACHE STRING "")
+set(abc "789" CACHE STRING "")
 message("Variable from cache: ${abc}")
[usage-of-variables]> cp double-set/2/CMakeLists.txt double-set/
[usage-of-variables]> cmake -Hdouble-set -B_builds
Variable from cache: 123
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds
[usage-of-variables]> grep abc _builds/CMakeCache.txt
abc:STRING=123

3.6.2.3. -D

Cache variable can be set by -D command line option. Variable that set by -D option take priority over set(... CACHE ...) command.

[usage-of-variables]> cmake -Dabc=444 -Hdouble-set -B_builds
Variable from cache: 444
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds
[usage-of-variables]> grep abc _builds/CMakeCache.txt
abc:STRING=444

3.6.2.4. Initial cache

If there are a lot of variables to set it’s not so convenient to use -D. In this case user can define all variables in separate file and load it by -C:

# cache.cmake

set(A "123" CACHE STRING "")
set(B "456" CACHE STRING "")
set(C "789" CACHE STRING "")
# CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

message("A: ${A}")
message("B: ${B}")
message("C: ${C}")
[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -C initial-cache/cache.cmake -Hinitial-cache -B_builds
loading initial cache file initial-cache/cache.cmake
A: 123
B: 456
C: 789
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

3.6.2.5. Force

If you want to set cache variable even if it’s already present in cache file you can add FORCE:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(A "123" CACHE STRING "" FORCE)
message("A: ${A}")
[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -DA=456 -Hforce -B_builds
A: 123
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

This is quite surprising behavior for user and conflicts with the nature of cache variables that was designed to store variable once and globally.

Warning

FORCE usually is an indicator of badly designed CMake code.

3.6.2.6. Force as a workaround

FORCE can be used to fix the problem that described earlier:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(A "123")
set(A "456" CACHE STRING "")

message("A: ${A}")
[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hno-force-confuse -B_builds
A: 456
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds
[usage-of-variables]> cmake -Hno-force-confuse -B_builds
A: 123
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

With FORCE variable will be set even it’s already present in cache, so regular variable with the same name will be unset too each time:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(A "123")
set(A "456" CACHE STRING "" FORCE)

message("A: ${A}")
[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hforce-workaround -B_builds
A: 456
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds
[usage-of-variables]> cmake -Hforce-workaround -B_builds
A: 456
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

3.6.2.7. Cache type

Though type of any variable is always string you can add some hints which will be used by CMake-GUI:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(FOO_A "YES" CACHE BOOL "Variable A")
set(FOO_B "boo/info.txt" CACHE FILEPATH "Variable B")
set(FOO_C "boo/" CACHE PATH "Variable C")
set(FOO_D "abc" CACHE STRING "Variable D")

message("FOO_A (bool): ${FOO_A}")
message("FOO_B (file path): ${FOO_B}")
message("FOO_C (dir path): ${FOO_C}")
message("FOO_D (string): ${FOO_D}")

Run configure:

../../_images/01-generate.png

Variable FOO_A will be treated as boolean. Uncheck box and run configure:

../../_images/02-bool.png

Variable FOO_B will be treated as path to the file. Click on ...:

../../_images/03-filepath.png

Select file:

../../_images/04-change-filepath.png

Run configure:

../../_images/05-ok-filepath.png

Variable FOO_C will be treated as path to directory. Click on ...:

../../_images/06-path.png

Select directory:

../../_images/07-change-path.png

Run configure:

../../_images/08-ok-path.png

Variable FOO_D will be treated as string. Click near variable name and edit:

../../_images/09-string.png

Run configure:

../../_images/10-ok-string.png

Description of variable:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(FOO_A "YES" CACHE BOOL "Variable A")
set(FOO_B "boo/info.txt" CACHE FILEPATH "Variable B")
set(FOO_C "boo/" CACHE PATH "Variable C")
set(FOO_D "abc" CACHE STRING "Variable D")

message("FOO_A (bool): ${FOO_A}")
message("FOO_B (file path): ${FOO_B}")
message("FOO_C (dir path): ${FOO_C}")
message("FOO_D (string): ${FOO_D}")

Will pop-up as a hint for users:

../../_images/11-popup-description.png

CMake documentation

3.6.2.8. Enumerate

Selection widget can be created for variable of string type:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(FOO_CRYPTO "OpenSSL" CACHE STRING "Backend for cryptography")

set_property(CACHE FOO_CRYPTO PROPERTY STRINGS "OpenSSL;Libgcrypt;WinCNG")
../../_images/12-enum.png

CMake documentation

3.6.2.9. Internal

Variable with type INTERNAL will not be shown in CMake-GUI (again, real type is a string still):

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(FOO_A "123" CACHE STRING "")
set(FOO_B "456" CACHE INTERNAL "")
set(FOO_C "789" CACHE STRING "")
../../_images/13-gui-internal.png

Also such type of variable implies FORCE:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(FOO_A "123" CACHE INTERNAL "")
set(FOO_A "456" CACHE INTERNAL "")
set(FOO_A "789" CACHE INTERNAL "")

set(FOO_B "123" CACHE STRING "")
set(FOO_B "456" CACHE STRING "")
set(FOO_B "789" CACHE STRING "")

message("FOO_A (internal): ${FOO_A}")
message("FOO_B (string): ${FOO_B}")

Variable FOO_A will be set to 123 then rewritten to 456 because behavior is similar to variable with FORCE, then one more time to 789, so final result is 789. Variable FOO_B is a cache variable with no FORCE so first 123 will be set to cache, then since FOO_B is already in cache 456 and 789 will be ignored, so final result is 123:

[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hinternal-force -B_builds
FOO_A (internal): 789
FOO_B (string): 123
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

3.6.2.10. Advanced

If variable is marked as advanced:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(FOO_A "123" CACHE STRING "")
set(FOO_B "456" CACHE STRING "")
set(FOO_C "789" CACHE STRING "")

mark_as_advanced(FOO_B)

it will not be shown in CMake-GUI if Advanced checkbox is not set:

../../_images/14-gui-no-advanced.png ../../_images/15-gui-advanced.png

CMake documentation

3.6.2.11. Use case

The ability of cache variables respect user’s settings fits perfectly for creating project’s customization option:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(FOO_A "Default value for A" CACHE STRING "")
set(FOO_B "Default value for B")

message("FOO_A: ${FOO_A}")
message("FOO_B: ${FOO_B}")

Default value:

[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hproject-customization -B_builds
FOO_A: Default value for A
FOO_B: Default value for B
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

User’s value:

[usage-of-variables]> cmake -DFOO_A=User -Hproject-customization -B_builds
FOO_A: User
FOO_B: Default value for B
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

Note that such approach doesn’t work for regular CMake variable FOO_B:

[usage-of-variables]> cmake -DFOO_B=User -Hproject-customization -B_builds
FOO_A: User
FOO_B: Default value for B
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

3.6.2.12. Option

Command option can be used for creating boolean cache entry:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

option(FOO_A "Option A" OFF)
option(FOO_B "Option A" ON)

message("FOO_A: ${FOO_A}")
message("FOO_B: ${FOO_B}")
[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hoption -B_builds
FOO_A: OFF
FOO_B: ON
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds
[usage-of-variables]> grep FOO_ _builds/CMakeCache.txt
FOO_A:BOOL=OFF
FOO_B:BOOL=ON

CMake documentation

3.6.2.13. Unset

If you want to remove variable X from cache you need to use unset(X CACHE). Note that unset(X) will remove regular variable from current scope and have no effect on cache:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(X "123" CACHE STRING "X variable")
set(X "456")
message("[0] X = ${X}")

unset(X)
message("[1] X = ${X}")

unset(X CACHE)
message("[2] X = ${X}")

option(Y "Y option" ON)
set(Y OFF)
message("[0] Y = ${Y}")

unset(Y)
message("[1] Y = ${Y}")

unset(Y CACHE)
message("[2] Y = ${Y}")

When we have both cache and regular X variables regular variable has higher priority and will be printed:

[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hunset-cache -B_builds
[0] X = 456
[1] X = 123
[2] X =
[0] Y = OFF
[1] Y = ON
[2] Y =
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

Command unset(X) will remove regular variable so cache variable will be printed:

[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hunset-cache -B_builds
[0] X = 456
[1] X = 123
[2] X =
[0] Y = OFF
[1] Y = ON
[2] Y =
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

Command unset(X CACHE) will remove cache variable too. Now no variables left:

[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hunset-cache -B_builds
[0] X = 456
[1] X = 123
[2] X =
[0] Y = OFF
[1] Y = ON
[2] Y =
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

Since option do modify cache same logic applied here:

cmake_minimum_required(VERSION 2.8)
project(foo NONE)

set(X "123" CACHE STRING "X variable")
set(X "456")
message("[0] X = ${X}")

unset(X)
message("[1] X = ${X}")

unset(X CACHE)
message("[2] X = ${X}")

option(Y "Y option" ON)
set(Y OFF)
message("[0] Y = ${Y}")

unset(Y)
message("[1] Y = ${Y}")

unset(Y CACHE)
message("[2] Y = ${Y}")
[usage-of-variables]> rm -rf _builds
[usage-of-variables]> cmake -Hunset-cache -B_builds
[0] X = 456
[1] X = 123
[2] X =
[0] Y = OFF
[1] Y = ON
[2] Y =
-- Configuring done
-- Generating done
-- Build files have been written to: /.../usage-of-variables/_builds

3.6.2.14. Recommendation

Because of the global nature of cache variables and options (well it’s cache too) you should do prefix it with the name of the project to avoid clashing in case several projects are mixed together by add_subdirectory:

# top-level CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(zoo)

add_subdirectory(boo)
add_subdirectory(foo)
# foo/CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(foo)

option(FOO_FEATURE_1 "Enable feature 1" OFF)
option(FOO_FEATURE_2 "Enable feature 2" OFF)
# boo/CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(boo)

option(BOO_FEATURE_1 "Enable feature 1" ON)
option(BOO_FEATURE_2 "Enable feature 2" ON)

Besides the fact that both features can be set independently now also CMake-GUI will group them nicely:

../../_images/grouped.png

3.6.2.15. Summary

  • Use cache to set global variables
  • Cache variables fits perfectly for expressing customized options: default value and respect user’s value
  • Type of cache variable helps CMake-GUI users
  • Prefixes should be used to avoid clashing because of the global nature of cache variables