[cmake-developers] Idea for Multi-Toolchain Support

Kyle Edwards kyle.edwards at kitware.com
Mon Dec 17 15:18:39 EST 2018


Hello everyone,

One of the things that's long been requested of CMake is the ability to
have multiple toolchains - for instance, one host toolchain and one
cross toolchain, so that "utilities" needed for build can be built with
the host toolchain and then the "real" software can be built with the
cross toolchain.

To solve this problem, I would like to propose the creation of a new
first-class object type, the "toolchain" type, which would replace the
current variable-based system, similar to how imported targets replaced
variable-based usage requirements.

Every project would automatically receive one toolchain, the "DEFAULT"
toolchain, which would be either automatically configured or configured
based on CMAKE_TOOLCHAIN_FILE, just like the current system. New
toolchains could be added with the add_toolchain() command:

add_toolchain(CrossToolchain FILE /path/to/toolchain/file.cmake)

Then, executables and libraries could have a toolchain specified:

add_executable(BuildUtility TOOLCHAIN DEFAULT ...)
add_library(MyLibrary TOOLCHAIN CrossToolchain ...)

Note that the TOOLCHAIN argument is optional, and if omitted, the
DEFAULT toolchain is used.

If a project uses multiple toolchains, we could have the option to
rename the default toolchain with an alternative add_toolchain()
syntax:

add_toolchain(HostToolchain DEFAULT)

Rather than adding a new toolchain, this would simply rename the
"DEFAULT" toolchain to "HostToolchain". Then the toolchain
specification for each target could look like this:

add_executable(BuildUtility TOOLCHAIN HostToolchain ...)
add_library(MyLibrary TOOLCHAIN CrossToolchain ...)

Two new global read-only properties would be added: TOOLCHAINS and
DEFAULT_TOOLCHAIN. TOOLCHAINS would be a semicolon-separated list of
all registered toolchains, and DEFAULT_TOOLCHAIN would be the name of
the DEFAULT toolchain (which could be changed with the alternative
add_toolchain() syntax.)

The CMAKE_TOOLCHAIN_FILE format would be changed so that rather than
setting variables:

set(CMAKE_C_COMPILER /usr/bin/gcc)
set(CMAKE_C_COMPILER_ID gnu)
# etc.

it would instead set properties on the selected toolchain:

set_property(TOOLCHAIN ${CMAKE_SELECTED_TOOLCHAIN} PROPERTY C_COMPILER
/usr/bin/gcc)
set_property(TOOLCHAIN ${CMAKE_SELECTED_TOOLCHAIN} PROPERTY
C_COMPILER_ID gnu)
# etc.

where CMAKE_SELECTED_TOOLCHAIN is a variable passed to the toolchain
file either at the root or by the add_toolchain() command.

If you want to read the value of C_COMPILER, etc. then just use
get_property():

get_property(c_compiler TOOLCHAIN HostToolchain PROPERTY C_COMPILER)

Obviously this system would scale well to more than just two toolchains
- just use as many add_toolchain() commands as you need.

Backwards compatibility is going to be a challenge. Both the toolchain
file and the project have to be aware of the new toolchain system,
which means we have to handle four permutations:

1) old toolchain + old project
2) old toolchain + new project
3) new toolchain + old project
4) new toolchain + new project

I propose adding a policy that both the toolchain file and the project
can set separately, and which would have a slightly different meaning
in each one. If the toolchain is OLD and the project is NEW, then the
variables set by the toolchain file would be converted into properties
on the toolchain for the project. If the toolchain is NEW and the
project is OLD, then the properties on the toolchain would be converted
into variables in the project. If both the toolchain and project have
the same value, then no special conversion is required.

I would welcome everyone's feedback on this proposal. Obviously this is
a big change to how CMake handles toolchains, and would require a lot
of very deep refactoring.

Kyle


More information about the cmake-developers mailing list