# Inconsistent behavior of Ninja generator on first and subsequent cmake runs for CMAKE\_\<LANG\>\_STANDARD\_LIBRARIES

**URL:** https://discourse.cmake.org/t/inconsistent-behavior-of-ninja-generator-on-first-and-subsequent-cmake-runs-for-cmake-lang-standard-libraries/8359
**Category:** Code
**Tags:** os:windows, comp:msvc, gen:ninja
**Created:** [June 20, 2023, 8:55am UTC](https://discourse.cmake.org/t/inconsistent-behavior-of-ninja-generator-on-first-and-subsequent-cmake-runs-for-cmake-lang-standard-libraries/8359 "2023-06-20T08:55:43Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![krolli](https://discourse.cmake.org/user_avatar/discourse.cmake.org/krolli/32/3539_2.png) [@krolli](https://discourse.cmake.org/u/krolli)
#### Post date: [June 20, 2023, 8:55am UTC](https://discourse.cmake.org/t/inconsistent-behavior-of-ninja-generator-on-first-and-subsequent-cmake-runs-for-cmake-lang-standard-libraries/8359/1 "2023-06-20T08:55:43Z")

</div>

Hi, we are writing a custom MSVC toolchain (specifically for Visual Studio 2017) and while doing so, we’ve run into a problem where generated build.ninja file is different on first cmake run compared to subsequent runs.

After first run it generates following (stripped down for readability) build statement:

```auto
build test.exe: CXX_EXECUTABLE_LINKER__test_Debug CMakeFiles\test.dir\main.cpp.obj
  LINK_LIBRARIES = kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib

```

However, when build directory is regenerated, `LINK_LIBRARIES` variable setting disappears. Note, I have manully removed all variables except `LINK_LIBRARIES`, as they remain the same after regeneration and would just get in the way.

This is generally not a problem, as `link.exe` will include those libraries in default libraries set by default, so as long as they are found using library search paths, things work and nothing needs to be mentioned on the command line.

We have noticed this because in our toolchain file we set `CMAKE_<LANG>_STANDARD_LIBRARIES` to contain these default libraries:

```auto
set(CMAKE_C_STANDARD_LIBRARIES
    kernel32.lib
    user32.lib
    gdi32.lib
    winspool.lib
    shell32.lib
    ole32.lib
    oleaut32.lib
    uuid.lib
    comdlg32.lib
    advapi32.lib
)
set(CMAKE_CXX_STANDARD_LIBRARIES ${CMAKE_C_STANDARD_LIBRARIES})

```

What happened was that builds would succeed without any problem after first build directory generation, but then after build directory got regenerated, builds would fail. Looking into it, we found out that regenerating changed the `LINK_LIBRARIES` in `build.ninja` file to following:

```auto
build test.exe: CXX_EXECUTABLE_LINKER__test_Debug CMakeFiles\test.dir\main.cpp.obj
  LINK_LIBRARIES = kernel32.lib;user32.lib;gdi32.lib;winspool.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;comdlg32.lib;advapi32.lib

```

That is, instead of separating libraries using spaces, it uses `;` (cmake list syntax).

Based on this, it looks like the behavior is to

- on first generation, ignore `CMAKE_<LANG>_STANDARD_LIBRARIES` and use hard-coded value
- on subsequent generation, use `CMAKE_<LANG>_STANDARD_LIBRARIES` assuming it holds a string, rather than a list

Now the discrepancy between first and subequent run seems like a bug, but it would be nice to hear someone else’ opinion on the matter before reporting it as such.

Treating `CMAKE_<LANG>_STANDARD_LIBRARIES` as string, rather than list, may be intended, but it seems to be inconsistent with `CMAKE_<LANG>_STANDARD_INCLUDE_DIRECTORIES`, which is treated as list. Should that also be considered a bug? On the other hand, `CMAKE_<TARGET_TYPE>_LINKER_FLAGS_INIT` are also treated as string rather than list, but at least the behavior seems to be consistent and first and subsequent cmake runs.

Note, as a workaround, we can set `CMAKE_<LANG>_STANDARD_LIBRARIES` as string using following:

```auto
string(JOIN " " CMAKE_C_STANDARD_LIBRARIES
    kernel32.lib
    user32.lib
    gdi32.lib
    winspool.lib
    shell32.lib
    ole32.lib
    oleaut32.lib
    uuid.lib
    comdlg32.lib
    advapi32.lib
)
set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES}")

```

This produces the same value of `LINK_LIBRARIES` in `build.ninja` for first and also subsequent runs, even though the process of arriving at that value is different.

---

<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:24pm UTC](https://discourse.cmake.org/t/inconsistent-behavior-of-ninja-generator-on-first-and-subsequent-cmake-runs-for-cmake-lang-standard-libraries/8359/2 "2023-06-20T14:24:48Z")

</div>

> [@krolli](#):
>
> in our toolchain file

Toolchain files are only read on the first configure (well, whenever a _new_ language is being enabled, really). Since it sets this up via a local variable, on subsequent runs it disappears because the toolchain file is not read and nothing sets the local variable.

---

<div class="post-metadata">

### Author: ![krolli](https://discourse.cmake.org/user_avatar/discourse.cmake.org/krolli/32/3539_2.png) [@krolli](https://discourse.cmake.org/u/krolli)
#### Post date: [June 20, 2023, 3:44pm UTC](https://discourse.cmake.org/t/inconsistent-behavior-of-ninja-generator-on-first-and-subsequent-cmake-runs-for-cmake-lang-standard-libraries/8359/3 "2023-06-20T15:44:31Z")

</div>

True, they should only be read on the first configure, but I also saw the value of that variable stored in the CMakeCache.txt which gives access to it in subsequent runs.

But now that you’ve brought it up, I experimented with it a little more. I added a `message()` call to toolchain file and `CMakeLists.txt` to both see what the value of `CMAKE_<LANG>_STANDARD_LIBRARIES` is and to see whether toolchain is indeed only read once. Findings are a bit surprising to me.

First interesting thing is that toolchain file is also read on subsequent configure runs, even if they were triggered due to changes in `CMakeLists.txt` and not manually from command line. On first run, toolchain file is executed twice, while on subsequent runs it executes only once. I did not expect it to be used in subsequent runs unless I enable more languages.

Second is that I think I know what is happening now. I made a wrong assumption that the way `CMAKE_<LANG>_STANDARD_LIBRARIES` is meant to be used is to set it in toolchain file and CMake (when it does compiler checks) will use this value and, if everything passes, store it in cache. But that doesn’t seem to be the case and instead the variable follows normal scoping rules, which appear inconsistent due to differences between first and subsequent runs. CMake just seems to ignore it during compiler checks and then stores into cache whatever it deems correct.

On first run, value set by toolchain file is shadowed by the value set in cache by compiler checks, and this cached value is then used to generated build files. However, because cache variable is already set and compiler checks don’t happen on subsequent runs, and because toolchain file is re-read on subsequent runs, setting of the variable in toolchain file will overshadow its value in cache and reach generated build files.

I guess this explains surprising behavior I was seeing and correct approach in this case should be to not set the `CMAKE_<LANG>_STANDARD_LIBRARIES` variable in toolchain file at all and leave compiler checks to set it to default. Though I still don’t know why is toolchain re-read on subsequent configure runs and whether that’s a mistake on my end or normal behavior.

---

<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: [June 21, 2023, 11:54am UTC](https://discourse.cmake.org/t/inconsistent-behavior-of-ninja-generator-on-first-and-subsequent-cmake-runs-for-cmake-lang-standard-libraries/8359/4 "2023-06-21T11:54:05Z")

</div>

> [@ben.boeckel](#):
>
> Toolchain files are only read on the first configure (well, whenever a _new_ language is being enabled, really). Since it sets this up via a local variable, on subsequent runs it disappears because the toolchain file is not read and nothing sets the local variable.

Are you sure about that? This doesn’t sound right. Toolchain files frequently (I’d go so far as to say usually) set non-cache variables. I’m pretty sure they will always be read at least once on every CMake run. It may be read more times on the first run, since it gets used in `try_compile()` calls when enabling a new language that hasn’t been enabled in that build directory before.

---

<div class="post-metadata">

### Author: ![krolli](https://discourse.cmake.org/user_avatar/discourse.cmake.org/krolli/32/3539_2.png) [@krolli](https://discourse.cmake.org/u/krolli)
#### Post date: [June 21, 2023, 12:26pm UTC](https://discourse.cmake.org/t/inconsistent-behavior-of-ninja-generator-on-first-and-subsequent-cmake-runs-for-cmake-lang-standard-libraries/8359/5 "2023-06-21T12:26:31Z")

</div>

I was trying to find some official documentation on when is toolchain file used exactly, but I couldn’t. I think the idea (at least for me) came from

- toolchain file only needs to be specified on first run
- toolchain file is invoked on first `project()` call or when enabling languages that weren’t enabled before

But that doesn’t imply that it is called _only_ when `project()` is called or language is enabled.

---

<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 25, 2023, 7:44pm UTC](https://discourse.cmake.org/t/inconsistent-behavior-of-ninja-generator-on-first-and-subsequent-cmake-runs-for-cmake-lang-standard-libraries/8359/6 "2023-06-25T19:44:58Z")

</div>

My mental model could be wrong… Maybe I’m improperly extrapolating from/conflating with “make sure you first-configure with your toolchain file of choice”…
