# Best way of adding compiler flags in toolchain

**URL:** <https://discourse.cmake.org/t/best-way-of-adding-compiler-flags-in-toolchain/6452>\
**Category:** Code\
**Created:** [September 9, 2022, 6:54pm UTC](https://discourse.cmake.org/t/best-way-of-adding-compiler-flags-in-toolchain/6452 "2022-09-09T18:54:31Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![martijntje](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/838e76/32.png) [@martijntje](https://discourse.cmake.org/u/martijntje)\
**Post date:** [September 9, 2022, 6:54pm UTC](https://discourse.cmake.org/t/best-way-of-adding-compiler-flags-in-toolchain/6452/1 "2022-09-09T18:54:31Z")

</div>

I’m writing a toolchain file to cross-compile and I need to set some compiler flags (e.g. `-arch x86_64`).  
Now I’m wondering what the best way is to add those flags.

It works if I use `add_compile_options` and `add_link_options`. There’s also the options to set `CMAKE_CXX_FLAGS` and `CMAKE_EXE_LINKER_FLAGS` as cache variables - which I read in [this old post](https://cmake.org/pipermail/cmake/2012-January/048429.html).

However, I’ve also seen [CMAKE\_\<LANG\>\_FLAGS\_INIT](https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS_INIT.html), which on paper looks like _exactly_ what I want. However, if I do that it seems that it’s completely ignored.

Is there another way, or do I need to do something specific to make the `*_INIT` options work correctly.

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [September 9, 2022, 11:28pm UTC](https://discourse.cmake.org/t/best-way-of-adding-compiler-flags-in-toolchain/6452/2 "2022-09-09T23:28:11Z")

</div>

The `CMAKE_<LANG>_FLAGS_INIT` variables will only have an effect the first time CMake is run in a build directory. After that, the `CMAKE_<LANG>_FLAGS` variables will already be set and `CMAKE_<LANG>_FLAGS_INIT` gets ignored. I also mention the following in my Professional CMake book, which may also be relevant to you here:

> Unfortunately, there are some inconsistencies in how CMake combines developer-specified `..._INIT` options with the defaults it normally provides. In most cases, CMake will append further options to those specified by `...INIT` variables, but with some platform/compiler combinations (particularly older or less frequently used ones), developer-specified `..._INIT` values can be discarded. This stems from the history of these variables, which used to be for internal use only and always unilaterally set the `..._INIT` values. From CMake 3.7, the `..._INIT` variables were documented for general use and the behavior was switched to appending rather than replacing for the commonly used compilers. The behavior for very old or no longer actively maintained compilers was left unmodified.

All that said, the `CMAKE_<LANG>_FLAGS_INIT` variables probably still are the most appropriate way to do what you’re trying to achieve. I’d only look for a different method if you’re using a toolchain where CMake doesn’t handle those variables in the way that you need them to.

---

<div class="post-metadata">

**Author:** ![martijntje](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/838e76/32.png) [@martijntje](https://discourse.cmake.org/u/martijntje)\
**Post date:** [September 10, 2022, 11:46am UTC](https://discourse.cmake.org/t/best-way-of-adding-compiler-flags-in-toolchain/6452/3 "2022-09-10T11:46:24Z")

</div>

Turns out it was something completely else. I was setting `CMAKE_CXX_FLAGS_INIT` and `CMAKE_EXE_LINKER_FLAGS_INIT`, but I was _not_ setting `CMAKE_C_FLAGS_INIT`. Since I did not specify languages in my `project()` call, CMake defaulted to both C and CXX, and it tried to compile and link a simple C program.

This didn’t work because none of the required flags (e.g. `-arch ...`) was getting set for the _compilation_, but it was getting set for the linker, which then got fed an object file with the wrong architecture.

I’ve now managed to get it to work, but I am still running into a strange issue. It seems that the flags I set in `CMAKE_CXX_FLAGS_INIT` are _also_ getting fed during the link step, which leads to warnings, since I use the `-nostdinc++` flag which is only relevant for compilation, but not for linking.

If I use `add_compile_options`, the flags are _only_ added for compilation and _not_ for linking, which is exactly what I want. Is there a way to avoid having CMake mis-use the flags for linking and still use the `CMAKE_<LANG>_FLAGS_INIT`?

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [September 10, 2022, 10:55pm UTC](https://discourse.cmake.org/t/best-way-of-adding-compiler-flags-in-toolchain/6452/4 "2022-09-10T22:55:37Z")

</div>

Sometimes it’s less clear cut whether a particular flag is more appropriately set in a toolchain file or in the project. One way of looking at it is that the toolchain file should specify the things that _must_ be set for a toolchain to be able to build anything at all for the target platform. Projects can then add further flags that tailor the compilation and linking of their targets. Ask yourself the question “Could I use this toolchain file with any other project building for the same target platform?”.

A flag like `nostdinc++` falls into a bit of a grey area. To me, it probably belongs in the project, since different projects (even different targets within the same project) might or might not need this flag. But I’ve also seen cases where flags of this nature are set in toolchain files, which might be appropriate in tightly controlled company environments where the toolchain files might be tied to specific builds.

I mention the above since it sounds like the flag you’re having trouble with might be better specified in the project anyway, in which case `add_compile_options()` or `target_compile_options()` could give you the behavior you ultimately need. I think the variables like `CMAKE_C_FLAGS` may end up being passed to the linker as well, but I don’t recall the exact behavior and whether it is even consistent across toolchains.

---

<div class="post-metadata">

**Author:** ![martijntje](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/838e76/32.png) [@martijntje](https://discourse.cmake.org/u/martijntje)\
**Post date:** [January 4, 2023, 9:27am UTC](https://discourse.cmake.org/t/best-way-of-adding-compiler-flags-in-toolchain/6452/5 "2023-01-04T09:27:03Z")

</div>

Well, the point is that this is specifically made for cross-compiling using a specific set of libraries/headers that work for the target platform. It’s necessary to set `nostdinc++` so that the compiler won’t try to include the standard library from its regular path (which, of course, won’t work since it doesn’t matches what’s on the target platform).

So this toolchain will never ever work _without_ that flag. For me that feels like a solid reason why it _should_ be in the toolchain file.

Which brings me back to my previous question: How can I set compiler flags in the toolchain file without them being fed during the linker step? I add the compiler flags using `CMAKE_CXX_FLAGS_INIT`, but that also appears during linking (which is unwanted). Why does it work when I use `add_compile_options`? From the documentation they should behave similar.

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [January 4, 2023, 9:43pm UTC](https://discourse.cmake.org/t/best-way-of-adding-compiler-flags-in-toolchain/6452/6 "2023-01-04T21:43:20Z")

</div>

> [@martijntje](#):
>
> …How can I set compiler flags in the toolchain file without them being fed during the linker step? I add the compiler flags using `CMAKE_CXX_FLAGS_INIT` , but that also appears during linking (which is unwanted)…

The linker is typically invoked via the compiler front end. That’s why `CMAKE_C_FLAGS` and `CMAKE_CXX_FLAGS` can end up being used on the linker command line as well. There was a discussion about this recently either here in this forum or in the gitlab issue tracker. You could go searching for that if you want a more detailed discussion.

> [@martijntje](#):
>
> Why does it work when I use `add_compile_options`? From the documentation they should behave similar.

I don’t know the reasoning behind why the `CMAKE_<LANG>_FLAGS` variables and the properties set by commands like `add_compile_options()` behave differently in this regard.
