# setting c++ standard from target\_compile\_option goes for higher standard

**URL:** <https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147>\
**Category:** Usage\
**Created:** [February 21, 2024, 11:14am UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147 "2024-02-21T11:14:44Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [February 21, 2024, 11:14am UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/1 "2024-02-21T11:14:44Z")

</div>

I recently upgrade my gcc to a version whose default dialect is C++17. Yet, for some specific use cases I’d like to use older standard but with

```cmake
target_compile_options(${TARGET_NAME} PUBLIC $<$<COMPILE_LANGUAGE:CXX>:cxx_std_14)

```

I’ve got `-std=c++17` appended to the compilation flags.  
I had open an [related issue](https://gitlab.kitware.com/cmake/cmake/-/issues/22620) a long time ago, which I have since forgotten. If I understand correctly `cxx_std_yy` means _at least_ version `yy`.

How can I have _exactly_ version `yy`, enforcing modern cmake?

---

<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:** [February 27, 2024, 1:50pm UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/2 "2024-02-27T13:50:34Z")

</div>

> [@adaldev](#):
>
> How can I have _exactly_ version `yy`, enforcing modern cmake?

AFAIK, you cannot. The best you can do is error in a header if the C++ version is “too new”.

Your bit doesn’t work because `cxx_std_14` is a compile _feature_, not an option. Use:

```cmake
target_compile_features(${TARGET_NAME} PUBLIC cxx_std_14)

```

---

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [February 27, 2024, 2:17pm UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/3 "2024-02-27T14:17:16Z")

</div>

My bad, I actually meant `target_compile_features`.  
  
Is the behavior the same with the “old way” (in tutorial, langage dialect is directly set from CMAKE variables)? I didn’t test.

It’s a shame. My actual use case is that I write code that might have to be supported by old compiler for which I know, for sure, that the langage standard is limited, yet I don’t have always such a compiler at hand. My code is shipping, sometime, alternate implementation according to the langage level and I would have prefered to test old version through cmake settings, not through `#define`. I agree it’s probably a matter of state.

Yet giving more than what is asked for is not always a gift… It should be debatable but it can lead to (bad) surprises. An “At least” option should be better. When one is checking a tool or dependency version, he has “==”, “more” or “less” option (in various flavor), hasn’t he?

---

<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:** [February 27, 2024, 2:33pm UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/4 "2024-02-27T14:33:41Z")

</div>

> [@adaldev](#):
>
> An “At least” option should be better. When one is checking a tool or dependency version, he has “==”, “more” or “less” option (in various flavor), hasn’t he?

Yes, however this ends up just setting up update hazards for the future. You end up having to cut a new release just to support new dependencies (that upgrade on their own schedule). If older compilers matter, test them directly in CI. VTK, ParaView, and CMake all have builds that actually use the old compilers instead of relying on new compilers being told “use an older standard”. Bug fixes get backported to old standards in new compilers; it doesn’t meant that old compilers actually work.

---

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [March 5, 2024, 2:42pm UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/5 "2024-03-05T14:42:14Z")

</div>

On second thought, I agree with your counter-argument.  
Regards  
A.

---

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [March 7, 2024, 4:30pm UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/6 "2024-03-07T16:30:41Z")

</div>

ah, additional question: Is there a way to retrieve the actual dialect used? At least for information purpose, it would be very useful for me to know, for instance, that C++17 has been used instead of a requested C++14, without scanning the issued compiler command line.

regards  
A.

---

<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:** [March 7, 2024, 6:20pm UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/7 "2024-03-07T18:20:12Z")

</div>

The only reliable way is to check the value of the `__cplusplus` preprocessor definition. Even with a command line, if there is no `-std=` flag, you’re left with “whatever the default of the compiler is”.

---

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [March 8, 2024, 8:31am UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/8 "2024-03-08T08:31:10Z")

</div>

Another thought is that I happened to realize that an unexpected standard was used because I saw in my compile line a `-std=c++17` while I requested a `c++14`. As the command line is constructed by CMake it should be it that is adding the option? Isn’t it? In this case there must be some compiler inspection within CMake that helps to get that?

A.

[EDIT] on a minimal example, inspecting CMAKE variable produced during configuration and generation, I found these ones:

```cmake
-- CMAKE_CXX_STANDARD_COMPUTED_DEFAULT=17
-- CMAKE_CXX_STANDARD_DEFAULT=17

```

Can’t they be used? I don’t know from which point they are available yet.  
[EDIT2] They don’t seem to be documented…

---

<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:** [March 29, 2024, 11:36am UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/9 "2024-03-29T11:36:20Z")

</div>

[`CMAKE_<LANG>_STANDARD_DEFAULT`](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_STANDARD_DEFAULT.html) is documented.

---

<div class="post-metadata">

**Author:** ![adaldev](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/a/9dc877/32.png) [@adaldev](https://discourse.cmake.org/u/adaldev)\
**Post date:** [March 29, 2024, 12:11pm UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/10 "2024-03-29T12:11:37Z")

</div>

Great, thanks,

For my culture, what is the difference with the other one? (so far, I only found them identical).

---

<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:** [March 29, 2024, 1:31pm UTC](https://discourse.cmake.org/t/setting-c-standard-from-target-compile-option-goes-for-higher-standard/10147/11 "2024-03-29T13:31:12Z")

</div>

It looks to be extracted from the `try_compile` to extract compiler information. It might be a way to detect things like `-std=c++17` in the set of default flags. I would just ignore it because it is undocumented and seems to just be used internally as an intermediate value.
