[CMake] dependencies of cross compiliations

Eric Noulard eric.noulard at gmail.com
Tue Nov 27 13:55:56 EST 2018


Le mar. 27 nov. 2018 à 11:28, Rolf Eike Beer <eike at sf-mail.de> a écrit :

> Am 2018-11-09 10:04, schrieb Torsten Robitzki:
> > Hi,
> > I hope this question was not asked before. I work in the embedded
> > field and there it is usually to have at least two different build
> > platforms. The Host platform, where unit tests are build (and where
> > CMake is running) and an embedded Target platform, where targets are
> > build with a cross compiler. Sometimes such a system comes with
> > self-written tools that are build and run on the Host platform to
> > build a target for the embedded Target platform (adding meta data to a
> > binary to be used by a bootloader for example).
> >
> > Usually I have two different build folders, one for the Host platform
> > and one for the Target platform, using different calls to cmake to
> > choose from a set of tools and targets. But when using this approach,
> > it is necessary that the Host platform build ran before the Target
> > platform build, so that tools that are required for the Target
> > platform are build during the Host target build.
> >
> > One solution I’ve came up with, is to build the required tools during
> > the Target platform build, using an add_custom_target() to invoke the
> > Target compiler directly. This works fine, as long as the tools are
> > basically build just out of a couple of files.
> >
> > What would be the „CMake-Way“ to add the tools (that have to be build
> > on the Target platform) as dependency to targets that have to be build
> > for the Target (cross compile) platform?
>
> TL;DR: there is not "good" way yet. But there should be one.
>
>
I do agree with that quote I was quite surprised (a long time ago) that
CMake did not support cross-compiling.
Back then I was using recursive hand-written makefiles for cross-compiling.
When I wanted to build
the whole thing I only had to hit "make" and wait.

Moreover I think CMake cross-compiling support was biased by the fact CMake
wasn't designed for that initially.
Please don't take my remark as bare criticism I am using CMake for a long
time now, I do like CMake very much
and I was pleased to see the cross-compiling support coming.

However from my point of view and my cross-compiling experience when you
cross-compile you have:

1) the host compiler which is used to compile "host tools"
2) the target compiler (may be several of them) to "cross-compile"

My assumption are:
 a) when you cross-compile your build is a "whole" and you shouldn't have
to setup some superbuild
   structure for building host tools ht_exe and another for target1 tool
t1t_exe and another one for target2 tool t2t_exe.

 b) what you want is to build:
     ht_exe for the host
     possibly use ht_exe during the build to generate some [source] file
     t1t_exe for the [cross]target1
     t2t_exe for the [cross]target2

 c)  you seldomly compile the same source for the host AND the target, but
it may happen.

And you want to build all that stuff with a single configure+build command
AND take advantage
of fast and efficient parallel build for the **whole build**. I don't want
to

cd /build/for/host
ninja
cd /build/for/target1
ninja
etc...



>  Helpful would be a special
> variable for CMAKE_INSTALL_PREFIX as this needs a bit of attention (and
> a non-sysroot thing prefix in the toolchain file). Confused? Granted,
> here is an example:
>
> if (CMAKE_CROSSCOMPILING)
>      set(HOST_INSTALL_DIR "/some/where")
>      add_host_build(. host HOST_INSTALL_DIR)
> endif ()
> add_executable(magic magic.cpp)
> install(TARGETS magic DESTINATION bin) # installs both the host and the
> target tool!
> add_custom_command(OUTPUT ${CMAKE_CURRENT_BUILD_DIR}/foo.cpp COMMAND
> magic) # will call the host build
> if (NOT CMAKE_HOST_BUILD)
>      add_executable(foo ${CMAKE_CURRENT_BUILD_DIR}/foo.cpp)
>      install(TARGETS foo DESTINATION bin)
> endif ()
>

I get your point but I think we may try a more declarative way.

add_executable(magic magic.cpp)
install(TARGETS magic DESTINATION bin)
add_custom_command(OUTPUT ${CMAKE_CURRENT_BUILD_DIR}/foo.cpp COMMAND magic)
add_executable(foo ${CMAKE_CURRENT_BUILD_DIR}/foo.cpp)
install(TARGETS foo DESTINATION bin)

set_target_properties(magic PROPERTIES BUILD_TARGET "host;cross_target1")
set_target_properties(foo PROPERTIES BUILD_TARGET "cross_target1")

after that we know that `magic` is to be built both for "host" and
"cross_target1" whereas
`foo` is only for "cross_target1".

before that we may have to "declaratively" define what is cross_target1
(and may be cross_target2) with something like:

enable_cross_target(NAME cross_target1 TOOLCHAIN ${CMAKE_CURRENT_SOURCE
_DIR}/cmake/target1-toolchain.cmake)
enable_cross_target(NAME cross_target2 TOOLCHAIN ${CMAKE_CURRENT_SOURCE
_DIR}/cmake/target2-toolchain.cmake)
and assume "host" builtin target is the one coming from the command line.

each define_cross_target(..) will create a separate subdir in the build
tree (much like CMAKE_CFG_INTDIR is working for multi-config generators)
may something like ${CMAKE_CURRENT_BINARY_DIR}/${CROSS_TARGET_NAME} if we
assume cross target name are unique.

all cmake command (install, add_executable, add_library, etc...) shall know
that a target is to be build for the host and/or cross target1
and/or cross target2 etc...

add_custom_command COMMAND argument refering to a built target
always refer to "host target" because there is usually no need (or mean) to
execute cross target during the build anyway.

in the end you will have a project which specify all the target (exe, lib,
custom) the usual declarative "modern CMake" way
and you won't have your CMakeLists.txt filled with

IF(CMAKE_CROSSCOMPILING)

IF(NOT CMAKE_HOST_BUILD)

controls.

if you need cross_target specific CMAKE_XXXX variables, they should either
go in the target toolchain file
or should be put in with
cross_target_set(cross_target1 VARIABLE CMAKE_INSTALL_PREFIX "/opt/target1")

You may even decide that if a "build target" is not enabled because you
have something like:

if (CROSS_BUILD_TARGET1)
   enable_cross_target(NAME cross_target1 TOOLCHAIN ${CMAKE_CURRENT_SOURCE
_DIR}/cmake/target1-toolchain.cmake)
endif()

if (CROSS_BUILD_TARGET2)
   enable_cross_target(NAME cross_target2 TOOLCHAIN ${CMAKE_CURRENT_SOURCE
_DIR}/cmake/target2-toolchain.cmake)
endif()

The build could succeed and emit some warning telling that some "cross
target" were not built.

This should end up in a layout like this:
>
> /tmp/install/prefix/tools/bin/magic.exe # Windows host
> /tmp/install/prefix/sysroot/usr/bin/magic # Unix guest
> /tmp/install/prefix/sysroot/usr/bin/foo
>
> The toolchain file would look somehow like this:
>
> set(CMAKE_HOST_PREFIX prefix
> set(CMAKE_SYSROOT ${CMAKE_HOST_PREFIX}/sysroot)
>
> and the CMake command would look like this:
>
> cmake -D CMAKE_TOOLCHAIN_FILE=tc.cmake -D CMAKE_INSTALL_PREFIX=/usr -D
> CMAKE_HOST_INSTALL_PREFIX=tools ...
>

I think that most of the time specifying the toolchain on the command line
drives you to some superbuild structure.


>
> The wish-season is coming up, so that's sort of what I would like to
> have. Now it's your turn. No bikeshedding please, only deliveries ;)
>

I wish an integrated multi-target cross building support in CMake with
little or no flow-control scripting command in the CMakeLists.txt.

-- 
Eric
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://cmake.org/pipermail/cmake/attachments/20181127/c3025fd3/attachment.html>


More information about the CMake mailing list