Building Compile-time Tools When Cross-compiling


As part of my compilation process I need to run a custom build tool that parses XML files and generates a C++ header and source file, which are in turn included and compiled by the main executable. My build tool is an executable target within my CMake setup that the main executable references via add_custom_command().

This works great not only because my build tool gets automatically built and executed at the right time (i.e. before the generated source files are needed by the main executable’s build process), making iteration a breeze, but also because both my build tool and the main executable share the same libraries, which avoids building them twice.

Is this setup incompatible with cross-compilation?

Let’s say I am on a Windows host machine and want to cross-compile the main executable for Linux. My build tool needs to be built for Windows, as it will be executed on the host machine during the compilation process. But my main executable is being built for Linux, so it pulls in Linux-specific libraries (e.g. a system IO abstraction library that is used by both executables).

Now the sharing of libraries between the executables is problematic, as I would want to pull in different versions of each library (i.e. SystemIO_Windows for my build tool and SystemIO_Linux for the main executable; see “Library Setup” below).

I am aware of CMAKE_HOST_SYSTEM_NAME vs. CMAKE_SYSTEM_NAME, CMake toolchains, etc., but as far as I can tell neither addresses the issue of needing to pull in the same target multiple times with different build settings.

Is my only option removing my build tool from the build process and using it as a pre-built executable?


Library Setup

The “System” library’s CMakeLists.txt includes different files depending on which platform is being targeted, i.e. on Windows “System” would add only the Windows_IO.cpp file and on Linux the Linux_IO.cpp file. I cannot have both files added at the same time because when I am not cross-compiling, Linux_IO.cpp would fail to compile on Windows.


The technique discussed in the following is one way of handling this:

Why do you not use add_custom_command() and an preinstalled host tool like an idl compiler, or xslt transformator, …?

You may find an usage example here

I have simplified what the tool does since it’s not important to the problem at hand. Unfortunately, it has to be a custom tool.

I really enjoy the effortless iteration that including it as a dependent target in the larger CMakeLists.txt provides, but maybe that is not achievable when cross-compiling. Craig Scott’s solution, while inventive, might be too involved to implement. Especially when compared with simply pointing the custom command to a pre-built binary of the tool when cross-compiling.

VTK handles it this way:

Could ExternalProject be used instead in a super-build configuration, or not?

Yes, I’ve used ExternalProject to mix different compilers in the one project (firmware for an embedded device that gets included in a software package for the host platform). The stackoverflow Q&A I linked to mentions this is possible in its question, but was explicitly out of scope for that particular situation. For the question posted here, it could probably be made to work, but you may have a bit of fiddling to do in order to have your main build know where the build tool’s executable will be. Once you put something out into an ExternalProject, you become responsible for telling your main build where all its build artefacts are. In a true super build, you can usually do that by installing to a staging area and telling later ExternalProjects to look there in find_package(), etc. calls using CMAKE_PREFIX_PATH. Not sure this fits the use case here though.

1 Like

Hm, ExternalProject is an interesting approach. Unfortunately, the project I work on is philosophically not quite ready for a super build.

Thanks for the ideas everyone!

Thinking about using the ExternalProject functionality for the exact same purpose (compile a compiler with HOST compiler :wink: when everything else is compiled with TARGET compiler specified in Toolchain file) - this seems to work and produces the right ELF files.

However, when the external project has a source in the same repository as the main project, how do I specify the dependency and checking for out-of-date state? (After build, when changing the code of an external project and running just make or ninja will not recompile the external project and everything using it to compile.)

And also, can I somehow change the compiler before specifying new project() win multi-project build? (Project branches added with add_subdirectory().) I would like to set the compiler compiled as ExternalProject.

The results of ExternalProject are not available in the configure step project where its ExternalProject_add exists. CMake requires the compiler be available when it configures, so this would need to be a separate ExteralProject_add call in order to consume the host toolchain.

You are right, I forgot that CMake is testing the compiler during configure.

I guess in that case the Craig Scotts’s solution is applying to this scenario too.