CMAKE_BUILD_TYPE is both a normal and a cache variable

I am really confused by the following fact:

CMAKE_BUILD_TYPE is both a “normal” variable and a cache variable in CMake. Indeed, it appears both in the CMakeCache.txt, whose value detaults to an empty string, and in the output of the command cmake --help-variable CMAKE_BUILD_TYPE.

This is really confusing to me because If I have this line

if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()

in my CMakeLists.txt and I have not passed anything from the command line, then “CMAKE_BUILD_TYPE” will refer to the normal variable and expand to Release but it will instead be empty in the CMakeCache.txt

This works due to how CMake evaluates true and false values.

So CMAKE_BUILD_TYPE is a false value when it isn’t defined, or defined to an empty string, or a string that is considered to be false ( e.g. OFF, NO, and others listed here ).

So your CMake code goes into the if block and creates and sets the local variable CMAKE_BUILD_TYPE to Release. Since CMake variable expansion rules state that local variables are first looked up first, this will be used going forward for the current scope. You can read more about variable lookup rules at: https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#variables

1 Like

Thanks Rob, that is clear now. However, it is unclear to me on the reasong behind having CMAKE_BUILD_TYPE as both a CMake defined regulard variable and cache variable.
For instance, the CMake define regular variable CMAKE_CXX_STANDARD is only a regular variable and this is clear to me because it is something that must be set by the project and not a user configurable value.
For this reasong I would have made CMAKE_BUILD_TYPE only a cache variable,

There’s no way to make an only-cache variable; the local variable will always win. This allows projects to set local variables before add_subdirectory of a vendored project to separate usage from their own cached variables.