Embedded, mobile and multi-architecture builds all rely on toolchain files, and so do vcpkg and Conan.
A toolchain file is a CMake script loaded before the first project() call, passed with --toolchain file.cmake (or -DCMAKE_TOOLCHAIN_FILE=...). It describes the target system, as opposed to the host running the build:
CMAKE_SYSTEM_NAME(Linux,Windows,Android,Genericfor bare metal) andCMAKE_SYSTEM_PROCESSOR. SettingCMAKE_SYSTEM_NAMEis what tells CMake it is cross-compiling (CMAKE_CROSSCOMPILINGbecomes true).CMAKE_C_COMPILER/CMAKE_CXX_COMPILER, for exampleaarch64-linux-gnu-g++.CMAKE_SYSROOT: the target's headers and libraries.CMAKE_FIND_ROOT_PATHand theCMAKE_FIND_ROOT_PATH_MODE_*variables: search for libraries, headers and packages only in the target root, but for programs (code generators, tools) on the host.
Because the compiler is fixed at the first configure, switching toolchains requires a fresh build directory.
Things that break when cross-compiling: running freshly built executables during the build (code generators must be built for the host, or found as host tools), try_run checks, and tests (use CMAKE_CROSSCOMPILING_EMULATOR, e.g. qemu-aarch64, to run them).
Package managers use the same hook: vcpkg provides scripts/buildsystems/vcpkg.cmake as a toolchain that installs dependencies and adds them to the search path, and Conan generates conan_toolchain.cmake. A toolchain file can chain to another via include().
Example
# aarch64-linux.cmake (use: cmake -S . -B build-arm --toolchain aarch64-linux.cmake)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
set(CMAKE_SYSROOT /opt/sysroots/aarch64)
# libraries, headers and packages from the target; programs from the host
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# run target binaries (tests, gtest discovery) through an emulator
set(CMAKE_CROSSCOMPILING_EMULATOR qemu-aarch64;-L;/opt/sysroots/aarch64)
# vcpkg instead: cmake -S . -B build --toolchain $VCPKG_ROOT/scripts/buildsystems/vcpkg.cmakeRemember
- A toolchain file describes the target system and is loaded before project()
- CMAKE_SYSTEM_NAME turns on cross-compiling; FIND_ROOT_PATH modes separate host and target
- vcpkg and Conan integrate through toolchain files too
Watch out for
- Reusing a build directory after changing toolchain files; the compiler is cached at first configure, so start fresh.