It’s hard to recommend a “best practice” for this, since it depends on what your goals are. There are different approaches, such as that mentioned by @hsattler, but also others.
Toolchain files get called any time a language is enabled which wasn’t enabled before. Most of the time, this is just the first
project() call, but it can come later via explicit
enable_language() calls or another
project() call which adds more languages. The toolchain file also gets read for
try_compile() builds, which are separate sub-builds isolated from your main build. You probably don’t want the
try_compile() calls downloading their own separate copy of fetched contents, so you’d need to consider how to prevent that if you took the approach mentioned by @hsattler.
You can put toolchain files in a remote repo and have FetchContent download that remote repo before the first
project() call. The user can then select one of the downloaded toolchain files if they want to by passing the path to the toolchain file where it will be after download. This requires that you know where the toolchain file you want will be located, but if your remote repo has a flat structure and only has toolchains, it can be fairly straightforward. Overriding the default download location for the repo can also make it simpler. Here’s a slightly simplified example from the
FetchContent section of my book (Professional CMake: A Practical Guide):
You can then invoke
cmake like so:
cmake -DCMAKE_TOOLCHAIN_FILE=toolchains/beta_cxx.cmake ...
Note how we didn’t specify the full absolute path to the toolchain file. CMake will look in both the source directory and build directory when given a relative path for the toolchain file. The
FetchContent_Declare() call overrides the
SOURCE_DIR to place the downloaded toolchains in a
toolchains subdirectory below the top of the build tree, so our relative path will find the toolchain files with the simple relative path shown. You would typically only want to do this for situations where you know the subdirectory name you choose will never clash with other parts of the project which may try to do the same thing (think about hierarchical projects), such as in a company environment where the set of projects that may be involved in a build is well known and under your control.
An advantage of putting your toolchain files in a dedicated repo like this is that the user is still free to choose whether they want to actually use the supplied toolchains or not. If they want to try out a different toolchain file, they can specify that on their
cmake command line instead of one of the toolchain files from the downloaded repo. They are still free to have their own toolchain file refer to things inside the downloaded toolchains repo. This might be handy when experimenting with a new or updated toolchain file.