239 lines · plain
1===================================================================2How to cross-compile Clang/LLVM using Clang/LLVM3===================================================================4 5Introduction6------------7 8This document contains information about building LLVM and9Clang on a host machine, targeting another platform.10 11For more information on how to use Clang as a cross-compiler,12please check https://clang.llvm.org/docs/CrossCompilation.html.13 14This document describes cross-building a compiler in a single stage, using an15existing ``clang`` install as the host compiler.16 17.. note::18 These instructions have been tested for targeting 32-bit ARM, AArch64, or19 64-bit RISC-V from an x86_64 Linux host. But should be equally applicable to20 any other target.21 22Setting up a sysroot23--------------------24 25You will need a sysroot that contains essential build dependencies compiled26for the target architecture. In this case, we will be using CMake and Ninja on27a Linux host and compiling against a Debian sysroot. Detailed instructions on28producing sysroots are outside of the scope of this documentation, but the29following instructions should work on any Linux distribution with these30pre-requisites:31 32 * ``binfmt_misc`` configured to execute ``qemu-user`` for binaries of the33 target architecture. This is done by installing the ``qemu-user-static``34 and ``binfmt-support`` packages on Debian-derived distributions.35 * Root access (setups involving ``proot`` or other tools to avoid this36 requirement may be possible, but aren't described here).37 * The ``debootstrap`` tool. This is available in most distributions.38 39The following snippet will initialise sysroots for 32-bit Arm, AArch64, and4064-bit RISC-V (just pick the target(s) you are interested in):41 42 .. code-block:: bash43 44 sudo debootstrap --arch=armhf --variant=minbase --include=build-essential,symlinks stable sysroot-deb-armhf-stable45 sudo debootstrap --arch=arm64 --variant=minbase --include=build-essential,symlinks stable sysroot-deb-arm64-stable46 sudo debootstrap --arch=riscv64 --variant=minbase --include=build-essential,symlinks unstable sysroot-deb-riscv64-unstable47 48The created sysroot may contain absolute symlinks, which will resolve to a49location within the host when accessed during compilation, so we must convert50any absolute symlinks to relative ones:51 52 .. code-block:: bash53 54 sudo chroot sysroot-of-your-choice symlinks -cr .55 56 57Configuring CMake and building58------------------------------59 60For more information on how to configure CMake for LLVM/Clang,61see :doc:`CMake`. Following CMake's recommended practice, we will create a62`toolchain file63<https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html#toolchain-files>`_. 64 65The following assumes you have a system install of ``clang`` and ``lld`` that66will be used for cross compiling and that the listed commands are executed67from within the root of a checkout of the ``llvm-project`` git repository.68 69First, set variables in your shell session that will be used throughout the70build instructions:71 72 .. code-block:: bash73 74 SYSROOT=$HOME/sysroot-deb-arm64-stable75 TARGET=aarch64-linux-gnu76 CFLAGS=""77 78To customise details of the compilation target or choose a different79architecture altogether, change the ``SYSROOT``,80``TARGET``, and ``CFLAGS`` variables to something matching your target. For81example, for 64-bit RISC-V you might set82``SYSROOT=$HOME/sysroot-deb-riscv64-unstable``, ``TARGET=riscv64-linux-gnu``83and ``CFLAGS="-march=rva20u64"``. Refer to documentation such as your target's84compiler documentation or processor manual for guidance on which ``CFLAGS``85settings may be appropriate. The specified ``TARGET`` should match the triple86used within the sysroot (i.e. ``$SYSROOT/usr/lib/$TARGET`` should exist).87 88Then execute the following snippet to create a toolchain file:89 90 .. code-block:: bash91 92 cat - <<EOF > $TARGET-clang.cmake93 set(CMAKE_SYSTEM_NAME Linux)94 set(CMAKE_SYSROOT "$SYSROOT")95 set(CMAKE_C_COMPILER_TARGET $TARGET)96 set(CMAKE_CXX_COMPILER_TARGET $TARGET)97 set(CMAKE_C_FLAGS_INIT "$CFLAGS")98 set(CMAKE_CXX_FLAGS_INIT "$CFLAGS")99 set(CMAKE_LINKER_TYPE LLD)100 set(CMAKE_C_COMPILER clang)101 set(CMAKE_CXX_COMPILER clang++)102 set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)103 set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)104 set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)105 set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)106 EOF107 108 109Then configure and build by invoking ``cmake``:110 111 .. code-block:: bash112 113 cmake -G Ninja \114 -DCMAKE_BUILD_TYPE=Release \115 -DLLVM_ENABLE_PROJECTS="lld;clang" \116 -DCMAKE_TOOLCHAIN_FILE=$(pwd)/$TARGET-clang.cmake \117 -DLLVM_HOST_TRIPLE=$TARGET \118 -DCMAKE_INSTALL_PREFIX=$HOME/clang-$TARGET \119 -S llvm \120 -B build/$TARGET121 cmake --build build/$TARGET122 123These options from the toolchain file and ``cmake`` invocation above are124important:125 126 * ``CMAKE_SYSTEM_NAME``: Perhaps surprisingly, explicitly setting this127 variable `causes CMake to set128 CMAKE_CROSSCOMPIILING <https://cmake.org/cmake/help/latest/variable/CMAKE_CROSSCOMPILING.html#variable:CMAKE_CROSSCOMPILING>`_.129 * ``CMAKE_{C,CXX}_COMPILER_TARGET``: This will be used to set the130 ``--target`` argument to ``clang``. The triple should match the triple used131 within the sysroot (i.e. ``$SYSROOT/usr/lib/$TARGET`` should exist).132 * ``CMAKE_FIND_ROOT_PATH_MODE_*``: These `control the search behaviour for133 finding libraries, includes or binaries134 <https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html#finding-external-libraries-programs-and-other-files>`_.135 Setting these prevents files for the host being used in the build.136 * ``LLVM_HOST_TRIPLE``: Specifies the target triple of the system the built137 LLVM will run on, which also implicitly sets other defaults such as138 ``LLVM_DEFAULT_TARGET_TRIPLE``. For example, if you are using an x86_64139 host to compile for RISC-V, this will be a RISC-V triple.140 * ``CMAKE_SYSROOT``: The path to the sysroot containing libraries and headers141 for the target.142 * ``CMAKE_INSTALL_PREFIX``: Setting this avoids installing binaries compiled143 for the target system into system directories for the host system. It is144 not required unless you are going to use the ``install`` target.145 146See `LLVM's build documentation147<https://llvm.org/docs/CMake.html#frequently-used-cmake-variables>`_ for more148guidance on CMake variables (e.g. ``LLVM_TARGETS_TO_BUILD`` may be useful if149your cross-compiled binaries only need to support compiling for one target).150 151Working around a ninja dependency issue152---------------------------------------153 154If you followed the instructions above to create a sysroot, you may run into a155`longstanding problem related to path canonicalization in ninja156<https://github.com/ninja-build/ninja/issues/1330>`_. GCC canonicalizes system157headers in dependency files, so when ninja reads them it does not need to do158so. Clang does not do this, and unfortunately ninja does not implement the159canonicalization logic at all, meaning for some system headers with symlinks160in the paths, it can incorrectly compute a non-existing path and consider it161as always modified.162 163If you are suffering from this issue, you will find any attempt at an164incremental build (including the suggested command to build the ``install``165target in the next section) results in recompiling everything. ``ninja -C166build/$TARGET -t deps`` shows files in ``$SYSROOT/include/*`` that167do not exist (as the ``$SYSROOT/include`` folder does not exist) and you can168further confirm these files are causing ``ninja`` to determine a rebuild is169necessary with ``ninja -C build/$TARGET -d deps``.170 171A workaround is to create a symlink so that the incorrect172``$SYSROOT/include/*`` dependencies resolve to files within173``$SYSROOT/usr/include/*``. This works in practice for the simple174cross-compilation use case described here, but is not a general solution.175 176 .. code-block:: bash177 178 sudo ln -s usr/include $SYSROOT/include179 180Testing the just-built compiler181-------------------------------182 183Confirm the ``clang`` binary was built for the expected target architecture:184 185 .. code-block:: bash186 187 $ file -L ./build/aarch64-linux-gnu/bin/clang188 ./build/aarch64-linux-gnu/bin/clang: ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, for GNU/Linux 3.7.0, BuildID[sha1]=516b8b366a790fcd3563bee4aec0cdfcb90bb1c7, not stripped189 190If you have ``qemu-user`` installed you can test the produced target binary191either by invoking ``qemu-{target}-static`` directly:192 193 .. code-block:: bash194 195 $ qemu-aarch64-static -L $SYSROOT ./build/aarch64-linux-gnu/bin/clang --version196 clang version 21.0.0git (https://github.com/llvm/llvm-project cedfdc6e889c5c614a953ed1f44bcb45a405f8da)197 Target: aarch64-unknown-linux-gnu198 Thread model: posix199 InstalledDir: /home/asb/llvm-project/build/aarch64-linux-gnu/bin200 201Or, if binfmt_misc is configured (as was necessary for debootstrap):202 203 .. code-block:: bash204 205 $ export QEMU_LD_PREFIX=$SYSROOT; ./build/aarch64-linux-gnu/bin/clang --version206 clang version 21.0.0git (https://github.com/llvm/llvm-project cedfdc6e889c5c614a953ed1f44bcb45a405f8da)207 Target: aarch64-unknown-linux-gnu208 Thread model: posix209 InstalledDir: /home/asb/llvm-project/build/aarch64-linux-gnu/bin210 211Installing and using212--------------------213 214.. note::215 Use of the ``install`` target requires that you have set216 ``CMAKE_INSTALL_PREFIX`` otherwise it will attempt to install in217 directories under `/` on your host.218 219If you want to transfer a copy of the built compiler to another machine, you220can first install it to a location on the host via:221 222 .. code-block:: bash223 224 cmake --build build/$TARGET --target=install225 226This will install the LLVM/Clang headers, binaries, libraries, and other files227to paths within ``CMAKE_INSTALL_PREFIX``. Then tar that directory for transfer228to a device that runs the target architecture natively:229 230 .. code-block:: bash231 232 tar -czvf clang-$TARGET.tar.gz -C $HOME clang-$TARGET233 234The generated toolchain is portable, but requires compatible versions of any235shared libraries it links against. This means using a sysroot that is as236similar to your target operating system as possible is desirable. Other `CMake237variables <https://llvm.org/docs/CMake.html#frequently-used-cmake-variables>`_238may be helpful, for instance ``LLVM_STATIC_LINK_CXX_STDLIB``.239