# \`CMAKE\_\<LANG\>\_STANDARD\` and FetchContent/Cache variable interaction

**URL:** https://discourse.cmake.org/t/cmake-lang-standard-and-fetchcontent-cache-variable-interaction/8348
**Category:** Usage
**Created:** [June 19, 2023, 9:27am UTC](https://discourse.cmake.org/t/cmake-lang-standard-and-fetchcontent-cache-variable-interaction/8348 "2023-06-19T09:27:03Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![Lecris](https://discourse.cmake.org/user_avatar/discourse.cmake.org/lecris/32/3193_2.png) [@Lecris](https://discourse.cmake.org/u/Lecris)
#### Post date: [June 19, 2023, 9:27am UTC](https://discourse.cmake.org/t/cmake-lang-standard-and-fetchcontent-cache-variable-interaction/8348/1 "2023-06-19T09:27:03Z")

</div>

I have a question about how `CMAKE_<LANG>_STANDARD` and which takes precedence.

- Cache variable `-DCMAKE_<LANG>_STANDARD` vs `set()` (not cached):
  - Local variable wins because it shadows cached variable

- `set()` in parent project vs `set()` in FetchContented project:
  - FetchContent definition wins

- `set_target_properties` vs any value of `CMAKE_<LANG>_STANDARD`:
  - Property wins

* * *

So then what is and appropriate design:

- Always use `set()` (uncached) to set the project’s minimum standard, ~~allowing the user to bump/decrease the standard version~~. User cannot overwrite project’s standard
- ~~It is the importer’s responsibility to make sure the imported project satisfies their minimum version requirement. This is to avoid confusion like:~~ Project’s standard is always respected even if parent project has different standard
- How to set a recommended minimum STANDARD (e.g. C++23), and if compiler does not support it, default to a minimum standard that is supported (e.g. C++17)?

Am I missing some nuances in this?

---

<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: [June 19, 2023, 3:03pm UTC](https://discourse.cmake.org/t/cmake-lang-standard-and-fetchcontent-cache-variable-interaction/8348/2 "2023-06-19T15:03:43Z")

</div>

> [@Lecris](#):
>
> Cache variable `-DCMAKE_<LANG>_STANDARD` vs `set()` (not cached):

Local variables should always shadow cache variables.

> [@Lecris](#):
>
> `set()` in parent project vs `set()` in FetchContented project:

The more-local scope will win here (so the internal `FetchContent` project).

> [@Lecris](#):
>
> [Not experimented. To my reading target property wins?]

All the variable does is initialize the target property, so the property will win.

---

<div class="post-metadata">

### Author: ![Lecris](https://discourse.cmake.org/user_avatar/discourse.cmake.org/lecris/32/3193_2.png) [@Lecris](https://discourse.cmake.org/u/Lecris)
#### Post date: [June 19, 2023, 3:06pm UTC](https://discourse.cmake.org/t/cmake-lang-standard-and-fetchcontent-cache-variable-interaction/8348/3 "2023-06-19T15:06:07Z")

</div>

> [@ben.boeckel](#):
>
> Local variables should always shadow cache variables.

Well not if they are read during the build process right? But I did try this and it did not get shadowed to my surprise. I’ll update with an example.

---

<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: [June 19, 2023, 3:08pm UTC](https://discourse.cmake.org/t/cmake-lang-standard-and-fetchcontent-cache-variable-interaction/8348/4 "2023-06-19T15:08:58Z")

</div>

If you mean “during the build process” something that tries to peek into `CMakeCache.txt` and divine something…sure the cache is the only thing that exists at that point. An example would help a lot.

---

<div class="post-metadata">

### Author: ![Lecris](https://discourse.cmake.org/user_avatar/discourse.cmake.org/lecris/32/3193_2.png) [@Lecris](https://discourse.cmake.org/u/Lecris)
#### Post date: [June 19, 2023, 3:58pm UTC](https://discourse.cmake.org/t/cmake-lang-standard-and-fetchcontent-cache-variable-interaction/8348/5 "2023-06-19T15:58:29Z")

</div>

I have tried to replicate the environment [here](https://github.com/LecrisUT/mwe_cmake_standard), from an [earlier experiment](https://github.com/spglib/spglib/actions/runs/5303821244/jobs/9599719590#step:6:26), but it seems I cannot replicate. I might have not had the `CMAKE_C_STANDARD` set in that commit so it only took the value from the cache.

So in this case the values prescribed in the project always win. Then my confusion is resolved except for:

> [@Lecris](#):
>
> How to set a recommended minimum STANDARD (e.g. C++23), and if compiler does not support it, default to a minimum standard that is supported (e.g. C++17)?

Advice on that? How do I test the compiler feature? Do I have to do it on individual targets as:

```cmake
target_compile_features(mylib PUBLIC
    "$<$<COMPILE_FEATURES:cxx_std_23>:cxx_std_23>"
    "$<$<NOT:$<COMPILE_FEATURES:cxx_std_23>>:cxx_std_17>"
)

```

Is there an easier approach with global 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: [June 20, 2023, 2:31pm UTC](https://discourse.cmake.org/t/cmake-lang-standard-and-fetchcontent-cache-variable-interaction/8348/6 "2023-06-20T14:31:17Z")

</div>

I don’t think there’s an easier way to do it, no. However, I _think_ your genex does nothing useful as it will only say `cxx_std_23` if the linking target already has `cxx_std_23` available. I’d just use `cxx_std_17` and use `set(CMAKE_CXX_STANDARD 23)` when you want to test C++23.

---

<div class="post-metadata">

### Author: ![Lecris](https://discourse.cmake.org/user_avatar/discourse.cmake.org/lecris/32/3193_2.png) [@Lecris](https://discourse.cmake.org/u/Lecris)
#### Post date: [June 20, 2023, 3:11pm UTC](https://discourse.cmake.org/t/cmake-lang-standard-and-fetchcontent-cache-variable-interaction/8348/7 "2023-06-20T15:11:53Z")

</div>

> [@ben.boeckel](#):
>
> However, I _think_ your genex does nothing useful as it will only say `cxx_std_23` if the linking target already has `cxx_std_23` available. I’d just use `cxx_std_17` and use `set(CMAKE_CXX_STANDARD 23)` when you want to test C++23.

Hmm, that’s confusing. My understanding of that genex is that it tests the compiler for C++23 and if available it sets that as the standard, otherwise it sets it as C++17. The difference with `set(CMAKE_CXX_STANDARD 23)` is that if it’s not satisfied, it does not set an appropriate minimum standard. Or am I wrong and cmake goes through the standard list and it picks the first highest one that is satisfied?

---

<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: [June 20, 2023, 4:37pm UTC](https://discourse.cmake.org/t/cmake-lang-standard-and-fetchcontent-cache-variable-interaction/8348/8 "2023-06-20T16:37:13Z")

</div>

Based on my reading of [the docs](https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#compile-features):

> where `features` is a comma-separated list. Evaluates to `1` if all of the `features` are available for the ‘head’ target, and `0` otherwise.

the “available to the ‘head’ target” means “has in its compile feature list”.

> If this expression is used while evaluating the link implementation of a target and if any dependency transitively increases the required [`C_STANDARD`](https://cmake.org/cmake/help/latest/prop_tgt/C_STANDARD.html#prop_tgt:C_STANDARD) or [`CXX_STANDARD`](https://cmake.org/cmake/help/latest/prop_tgt/CXX_STANDARD.html#prop_tgt:CXX_STANDARD) for the ‘head’ target, an error is reported.

Means that increasing the standard while doing the query is going to raise an error.

So, basically: try it out and see if it works (my reading might indeed be inaccurate). Whatever the results, the docs could probably use some clarification.
