# CMAKE\_BUILD\_TYPE is both a normal and a cache variable

**URL:** https://discourse.cmake.org/t/cmake-build-type-is-both-a-normal-and-a-cache-variable/10664
**Category:** Usage
**Created:** [April 15, 2024, 3:59pm UTC](https://discourse.cmake.org/t/cmake-build-type-is-both-a-normal-and-a-cache-variable/10664 "2024-04-15T15:59:51Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![mredenti](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mredenti/32/4464_2.png) [@mredenti](https://discourse.cmake.org/u/mredenti)
#### Post date: [April 15, 2024, 3:59pm UTC](https://discourse.cmake.org/t/cmake-build-type-is-both-a-normal-and-a-cache-variable/10664/1 "2024-04-15T15:59:51Z")

</div>

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

---

<div class="post-metadata">

### Author: ![robert.maynard](https://discourse.cmake.org/user_avatar/discourse.cmake.org/robert.maynard/32/4_2.png) [@robert.maynard](https://discourse.cmake.org/u/robert.maynard)
#### Post date: [April 16, 2024, 1:42pm UTC](https://discourse.cmake.org/t/cmake-build-type-is-both-a-normal-and-a-cache-variable/10664/2 "2024-04-16T13:42:29Z")

</div>

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](https://cmake.org/cmake/help/latest/command/if.html#constant) ).

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](https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#variables)

---

<div class="post-metadata">

### Author: ![mredenti](https://discourse.cmake.org/user_avatar/discourse.cmake.org/mredenti/32/4464_2.png) [@mredenti](https://discourse.cmake.org/u/mredenti)
#### Post date: [April 17, 2024, 6:04pm UTC](https://discourse.cmake.org/t/cmake-build-type-is-both-a-normal-and-a-cache-variable/10664/3 "2024-04-17T18:04:39Z")

</div>

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,

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [April 17, 2024, 7:35pm UTC](https://discourse.cmake.org/t/cmake-build-type-is-both-a-normal-and-a-cache-variable/10664/4 "2024-04-17T19:35:58Z")

</div>

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.
