[CMake] CMAKE_TOOLCHAIN_FILE and projects

Hi,

I’m working on cross-compiling llvm and sub-projects to dynamically build Clang toolchain and associated libraries for an embedded project.

I’m starting with this mailing list, as I see the pattern using “config-ix.cmake” a common one; it’s found in all the sub-projects.

For those that are not aware, in CMake the standard approach for dealing with unique toolchains, system roots, etc is through the use of a CMAKE_TOOLCHAIN_FILE variable. This toolchain file is used to define the compiler, system type, architecture, sysroot, etc. It enables a simpler, and more versatile build script.

With tip of the tree on llvm and sub-projects now, when I use a toolchain file, I’m finding I have to make edits to the config-ix.cmake files. The issue is related to re-defining CMAKE_SYSROOT and the use of; among others:

set(CMAKE_REQUIRED_FLAGS “${CMAKE_REQUIRED_FLAGS} -nodefaultlibs”)

When this flag is used in stand-alone cross-compiled builds (using toolchain file to set the CMAKE_SYSROOT), it causes all the subsequent flag checks to fail.

I think leveraging an implied CMake toolchain file for sub-projects should be the preferred solution for “projects”, and it’s a fairly minor change to accommodate.

Stand-alone cross-compiled example for libunwind, compiler-rt, libcxxabi, and libcxx here (This config requires edits to the associated config-ix.cmake files for this to work):

https://github.com/jwinarske/flutter_embedded

Perhaps there is already a working solution to cross-compile the sub-projects from a single build invocation now? I found when cross-compiling compiler-rt as part of the Clang build, it fails due to sysroot issues. Something which the CMake toolchain file scenario would cleanly solve. The end goal being, when I set the list LLVM_TARGETS_TO_BUILD to desired targets, one could expect cross-compiled bits (as applicable) for each sub-project. This would greatly simplify building a toolchain config.

Perhaps I’m not clear on the current solution, and this already does what is needed for stand-alone cross-compiling? Until convinced otherwise, I think there is room for improvement here, and am willing to donate time to address it.

Cheers,

Joel Winarske

There are a couple different facets relating to cross-compilation, and the level of support we have today varies based on what you’re trying to do and which platforms you’re doing it with.

If you want to build a set of tools that run on your build host and support targeting one or more targets, and want the runtime libraries built for those targets, we have the llvm/runtimes directory which can support building runtime libraries (compiler-rt, libunwind, libc++abi, libc++, etc), for n-different platforms from a single build configuration. You can look at the Fuscia build configurations to see how that works (https://github.com/llvm-mirror/clang/tree/master/cmake/caches).

If you want to build a compiler and runtimes for a cross target, things get a bit trickier.

In that situation you probably need a 2-stage build where you build the host compiler and target runtimes similar to how the Fuscia builds work, then you’ll want to use that compiler and libraries to build the target compiler. You should be able to do that by providing a CMAKE_TOOLCHAIN_FILE to the second stage build configuration. We do support toolchain files for cross-targeting LLVM and Clang builds, and we have some documentation on it:

https://www.llvm.org/docs/GettingStarted.html#cross-compiling-llvm

Also for more general documentation on some of our more complicated builds see:

https://www.llvm.org/docs/AdvancedBuilds.html

-Chris

We actually do a full cross build of our (Fuchsia) toolchain from x86_64-linux-gnu to aarch64-linux-gnu. This is using the combination of Fuchsia CMake cache files that Chris pointed to and a set of CMake options that are set by our builder, here’s the portion of our build recipe that handles that: https://fuchsia.googlesource.com/infra/recipes/+/master/recipes/clang_toolchain.py#212, the LLVM CMake runtimes build knows how to handle the rest.

The way this works is we build the first stage for host (x86_64-linux-gnu), including runtimes libraries for host, in our case libc++/libc++abi/libunwind and compiler-rt (this is controlled by https://github.com/llvm-mirror/clang/blob/master/cmake/caches/Fuchsia.cmake#L50). We then use the first stage toolchain to build the second stage compiler for the target (aarch64-linux-gnu) as well as runtimes for all the targets we want to support (https://github.com/llvm-mirror/clang/blob/master/cmake/caches/Fuchsia-stage2.cmake#L36). This is the only difference from the native build where the runtimes would be built by the second stage compiler, not the first one.

Here is that builder: https://luci-milo.appspot.com/p/fuchsia/builders/luci.fuchsia.ci/clang-arm64-linux, you can also fetch the produced toolchain from GCS by using the “gsutil.upload” link, it’s just a zip archive.

Let me know if you have any questions, I’d be happy to give more pointers if needed.