[cmake-developers] Using multiple toolchains
Stephen Kelly
steveire at gmail.com
Thu Jul 4 10:03:08 EDT 2013
Brad King wrote:
> On 7/1/2013 1:26 PM, Stephen Kelly wrote:
>> I've pushed a proof-of-concept multiple-toolchains branch to my clone
>> which enables the use of multiple toolchains with cmake.
>
> Wow, that is a mind-blowing branch ;)
That's a good reaction :).
>> The idea is to use a separate cache and set of definition overrides for
>> each toolchain.
>
> That sounds a lot like a separate invocation of CMake for each
> toolchain, which is what one must do now.
It's not very similar.
* There is less for the buildsystem maintainer or invoker of the cmake
executable to do.
* The cmake-targets for the host and the target are 'closer together'. There
doesn't need to be a separate buildsystem of host tools.
>> One of the goals I have is to make it possible to use N different
>> toolchains, not just two.
>
> Currently we support only one toolchain per language per build tree,
> not even two. When one needs host tools we require two separate
> builds.
Correct. Or ExternalProject as you say below.
>> There's obviously a clash of output binary names, cmake target names and
>> make target names if the same library is going to be build for multiple
>> toolchains. That's something I have not yet attempted to solve.
>
> These among many other challenges await anyone that attempts your
> proposed approach.
... but only if the goal is N toolchains.
My approach comprises several steps:
1. Refactor cmake so that more that one toolchain can be available at
a time.
2. Make host+target builds possible in a single buildsystem by initializing
both the host and the target toolchain, specifying whether to find
dependencies in the host or the target, and specifying whether to build a
particular cmake-target for the host or for the target system. This does
not expose us to problems of clashes of cmake-target names for multiple
toolchains or problems of defining multiple per-toolchain make-targets
for a single cmake-target as all of those things remain impossible at
this step. This step requires some way to define such distinctions in
front-end CMakeLists.txt files. Possibly something like a toolchains()
command scoped to end with a endtoolchains() command.
3. Make it possible to define multiple toolchains to build a single target
for. Still only two toolchains are possible (host+target), but now we can
define that a single cmake-target created with add_executable should be
built for both the host and the target. Consider moc for example, which
might make sense to build for both so that target-on-target builds (or
target-in-target-vm builds) can be done. In addition to step two, this
step requires solving the disabmiguation problems of cmake-targets and
other problems that come from using multiple toolchains from one
cmake-target definition.
4. Make it possible to use N target toolchains. This takes advantage of the
solutions created in step 3. In addition to step 3, this step requires
deprecation of the undocumented CMAKE_TOOLCHAIN_FILE in favor of
something which can be a list, and it requires some way of attaching
names to toolchains. Projects using this have the disadvantage that there
is nothing but convention to standardise toolchain names. One project
might use RaspPi as a toolchain name in a CMakeLists.txt file, while
another uses RaspberryPi and yet another Raspbian. Qt has a similar issue
with device mkspec names.
> While the work in your branch has gotten
> impressively far, it also serves to demonstrate the inherent
> complexity of the proposed approach. IMO it is not worth exploring
> that approach further. Sorry.
That reaction is not what I was hoping for. :)
My branch makes a start mostly on steps 1 and 2 above, and to a small
extent, step 4. 80% of the motivation and value of multiple toolchains comes
from step 2, so I would happily truncate the other two as goals or leave
them to future exporation.
I don't think an inappropriate amount of work or fundamental change to cmake
is required to achieve step 2.
> Much of the multiple toolchains functionality can be accomplished by
> using ExternalProject to create a "superbuild" in which each inner
> project uses a different toolchain file. From that one can get to
> a single make invocation to drive everything. It doesn't need any
> fundamental changes in CMake.
I haven't used ExternalProject before today, though I was already aware of
the existence of it, having read various discussions about it on the mailing
lists. I added an example to my branch which uses it in an equivalent way
with a simple host+target buildsystem.
Apart from learning how to use it, which I documented with commits, I have
the following notes:
* The host compilations can be run in parallel, and the target compilations
can be run in parallel, but the host compilations can't be done in
parallel with the target compilations. A larger project than my example
would have compilations which do not depend on files generated by the
host_tool. This limitation is introduced by using ExternalProject but
would not be present in an implementation of my step 2.
* I wonder how the parallelization issue raised by Alan is handled:
http://thread.gmane.org/gmane.comp.programming.tools.cmake.user/47103/focus=47109
I build with make flags defined in my environment and having -jN
cause Nxnum_parallel_ExternalProjects jobs to be run instead of N is a bit
odd. That would not happen with my step 2.
* I need to be explicit about the dependencies between ExternalProjects,
instead of cmake figuring it out for me, as would happen with my step 2.
* The separation between the host and the target ExternalProjects is
unfortunate, and should not really be necessary.
* I needed to hardcode a relative path to the host build dir in order to get
to the exported targets file. It looks like it would be possible to use
ExternalProject_Get_Property to create another connection between the
host and target at the superbuild layer. This should not really be
necessary.
* The superbuild layer is an additional maintenance layer for the
maintainer and something sure to grow in complexity over time.
* With increasing complexity, there is sure to be more data transfer issues
and issues of escaping etc to think about by passing though the additional
cmake superbuild layer.
* Even if I'm not cross compiling, I have all of the above issues to deal
with. This just increases the barrier to cross-compiling, which is not
necessary.
ExternalProject is a rather large sledgehammer, and while I'm sure it's
useful and fully appropriate in many cases, in this case it seems to be
quite inelegant. In this case, we have only two elements in the superbuild,
both use cmake, neither need to be downloaded, they have strong connections
to each other, and the only need for separation comes from
building the targets with separate toolchains.
Implementing my step 2 above is a far more elegant solution, doesn't go far
enough to require difficult and significant redesign of cmake, and would be
quite a killer feature for a cross-platform, cross compiling tool. At KDAB
we do an increasing amount of embedded development and having a feature like
this would make it easier to convince customers to use cmake instead of
qmake+many kludges, which we usually have to deal with.
Thanks,
Steve.
More information about the cmake-developers
mailing list