# Is it good or bad practice to set the CMAKE\_TOOLCHAIN\_FILE from within CMakeLists.txt?

**URL:** <https://discourse.cmake.org/t/is-it-good-or-bad-practice-to-set-the-cmake-toolchain-file-from-within-cmakelists-txt/11297>\
**Category:** Code\
**Created:** [July 21, 2024, 4:33pm UTC](https://discourse.cmake.org/t/is-it-good-or-bad-practice-to-set-the-cmake-toolchain-file-from-within-cmakelists-txt/11297 "2024-07-21T16:33:50Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dennis\_Ferron](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dennis_ferron/32/2953_2.png) [@Dennis\_Ferron](https://discourse.cmake.org/u/Dennis_Ferron)\
**Post date:** [July 21, 2024, 4:33pm UTC](https://discourse.cmake.org/t/is-it-good-or-bad-practice-to-set-the-cmake-toolchain-file-from-within-cmakelists-txt/11297/1 "2024-07-21T16:33:50Z")

</div>

…as opposed to passing it on the CMake command line or in CMakePresets.json?

I moved from a computer which had VCPKG\_ROOT set to one that did not (although I have vcpkg on here). My CMAKE\_TOOLCHAIN\_FILE from my CMakePresets.json was no longer valid since I had it defined as `"$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"`.

I found a suggestion on the vcpkg Github discussions to use vcpkg from a submodule so that a local path could be used and to set CMAKE\_TOOLCHAIN\_FILE in the CMakeLists.txt:

> **[How do I set VCPKG\_ROOT · microsoft/vcpkg · Discussion #25394](https://github.com/microsoft/vcpkg/discussions/25394)**
>
> I am trying to make a CMake configuration where I dont need to link the vcpkg manually, so I need to use VCPKG\_ROOT. However it seems that this variable cannot be found. I am using a WSL Unbuntu 20...

From experimentation I think it can work, but it has to appear before the `project` directive (I think that’s what made the difference), or else it doesn’t work. However I’m wondering if this suggestion squares with CMake good practice. I’m trying to balance “batteries included / works out of the box” with not over-constraining how my projects can be built.

---

<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:** [July 21, 2024, 10:26pm UTC](https://discourse.cmake.org/t/is-it-good-or-bad-practice-to-set-the-cmake-toolchain-file-from-within-cmakelists-txt/11297/2 "2024-07-21T22:26:10Z")

</div>

In general, a project shouldn’t be setting `CMAKE_TOOLCHAIN_FILE` itself. That is normally something that the user should be in control of. They would normally set it either on the `cmake` command line or with a CMake preset. There are occasionally some scenarios where the project setting it can be justified, but those are typically restricted to tightly controlled company projects where the project must be built in a very specific way. Even then, presets are usually a better choice for such cases.

---

<div class="post-metadata">

**Author:** ![Chardrazle](https://discourse.cmake.org/user_avatar/discourse.cmake.org/chardrazle/32/4362_2.png) [@Chardrazle](https://discourse.cmake.org/u/Chardrazle)\
**Post date:** [June 11, 2025, 1:36pm UTC](https://discourse.cmake.org/t/is-it-good-or-bad-practice-to-set-the-cmake-toolchain-file-from-within-cmakelists-txt/11297/3 "2025-06-11T13:36:17Z")

</div>

Posting to closed issue because similar question, but requesting clarification.

It seems the `CMAKE_TOOLCHAIN_FILE` is somewhat special. Given a scenario that arguably falls under the “restricted to tightly controlled projects”, consider:

```auto
cmake_minimum_required(VERSION 4.0)

# Stamp out a fake toolchain file (just for this example).
file(WRITE tc.cmake [[
message("Loading TC: ${CMAKE_CURRENT_LIST_FILE}")
]])

set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_LIST_DIR}/tc.cmake")

option(TC OFF)

message(STATUS "TC entry: ${CMAKE_TOOLCHAIN_FILE}")
if(TC)
  # Try to wipe out all residue...
  unset(CMAKE_TOOLCHAIN_FILE)
  unset(CMAKE_TOOLCHAIN_FILE CACHE)

  set(CMAKE_TOOLCHAIN_FILE "something_that_does_not_exist.cmake")
  set(CMAKE_TOOLCHAIN_FILE "something_that_does_not_exist.cmake" CACHE FILEPATH "" FORCE) # Try everything
  message(STATUS "TC set: ${CMAKE_TOOLCHAIN_FILE}")
endif()

# Will instigate toolchain processing...
project(tc)

```

So, first configuration, `cmake .`, processes the _tc.cmake_ toolchain file. Splendid.  
We can:

```auto
$ grep TOOLCHAIN CMakeCache.txt 
CMAKE_TOOLCHAIN_FILE:FILEPATH=<redacted>/tc.cmake

```

Now try to reconfigure based on option: `cmake -DTC=ON .`  
The output will show cmake is still processing the _original_ _tc.cmake_ file.  
But:

```auto
$ grep TOOLCHAIN CMakeCache.txt 
CMAKE_TOOLCHAIN_FILE:FILEPATH=something_that_does_not_exist.cmake

```

So, although we’ve managed to update the cache, none of the generated build files actually refer to it. This can be seen by _grep_ping the Makefiles or Ninja build files.

So is it that once `CMAKE_TOOLCHAIN_FILE` is configured, then that’s it written in stone (well, unless the _CMakeCache.txt_ is deleted)?

---

<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 11, 2025, 9:44pm UTC](https://discourse.cmake.org/t/is-it-good-or-bad-practice-to-set-the-cmake-toolchain-file-from-within-cmakelists-txt/11297/4 "2025-06-11T21:44:26Z")

</div>

I don’t recall the details of what gets recorded where, but once you set a toolchain file for a build directory, you cannot change the toolchain file without clearing the build directory (or at least doing a `cmake --fresh ...` run to discard previously cached information).
