cb424d7448
verify-patch-sanity.py validates every active recipe .patch has internally- consistent hunk line counts — catching the 'malformed patch at line N' failure at commit/CI/preflight time instead of hours into a cook. This cycle hit that class three times (qtwaylandscanner, sddm, xwayland), each only discovered when cookbook tried to apply the patch. Running it across the repo found 29 latent malformed patches (validated against GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22'). They were harmless only because they sit in vendored recipes (baked, not re- applied) — but would fail on any version-bump re-derivation. --fix recounts the hunk headers (body untouched) and repaired all 29. Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test (test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats (empty placeholders, bare-@@ git hunks).
239 lines
10 KiB
ReStructuredText
239 lines
10 KiB
ReStructuredText
===================================================================
|
|
How to cross-compile Clang/LLVM using Clang/LLVM
|
|
===================================================================
|
|
|
|
Introduction
|
|
------------
|
|
|
|
This document contains information about building LLVM and
|
|
Clang on a host machine, targeting another platform.
|
|
|
|
For more information on how to use Clang as a cross-compiler,
|
|
please check https://clang.llvm.org/docs/CrossCompilation.html.
|
|
|
|
This document describes cross-building a compiler in a single stage, using an
|
|
existing ``clang`` install as the host compiler.
|
|
|
|
.. note::
|
|
These instructions have been tested for targeting 32-bit ARM, AArch64, or
|
|
64-bit RISC-V from an x86_64 Linux host. But should be equally applicable to
|
|
any other target.
|
|
|
|
Setting up a sysroot
|
|
--------------------
|
|
|
|
You will need a sysroot that contains essential build dependencies compiled
|
|
for the target architecture. In this case, we will be using CMake and Ninja on
|
|
a Linux host and compiling against a Debian sysroot. Detailed instructions on
|
|
producing sysroots are outside of the scope of this documentation, but the
|
|
following instructions should work on any Linux distribution with these
|
|
pre-requisites:
|
|
|
|
* ``binfmt_misc`` configured to execute ``qemu-user`` for binaries of the
|
|
target architecture. This is done by installing the ``qemu-user-static``
|
|
and ``binfmt-support`` packages on Debian-derived distributions.
|
|
* Root access (setups involving ``proot`` or other tools to avoid this
|
|
requirement may be possible, but aren't described here).
|
|
* The ``debootstrap`` tool. This is available in most distributions.
|
|
|
|
The following snippet will initialise sysroots for 32-bit Arm, AArch64, and
|
|
64-bit RISC-V (just pick the target(s) you are interested in):
|
|
|
|
.. code-block:: bash
|
|
|
|
sudo debootstrap --arch=armhf --variant=minbase --include=build-essential,symlinks stable sysroot-deb-armhf-stable
|
|
sudo debootstrap --arch=arm64 --variant=minbase --include=build-essential,symlinks stable sysroot-deb-arm64-stable
|
|
sudo debootstrap --arch=riscv64 --variant=minbase --include=build-essential,symlinks unstable sysroot-deb-riscv64-unstable
|
|
|
|
The created sysroot may contain absolute symlinks, which will resolve to a
|
|
location within the host when accessed during compilation, so we must convert
|
|
any absolute symlinks to relative ones:
|
|
|
|
.. code-block:: bash
|
|
|
|
sudo chroot sysroot-of-your-choice symlinks -cr .
|
|
|
|
|
|
Configuring CMake and building
|
|
------------------------------
|
|
|
|
For more information on how to configure CMake for LLVM/Clang,
|
|
see :doc:`CMake`. Following CMake's recommended practice, we will create a
|
|
`toolchain file
|
|
<https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html#toolchain-files>`_.
|
|
|
|
The following assumes you have a system install of ``clang`` and ``lld`` that
|
|
will be used for cross compiling and that the listed commands are executed
|
|
from within the root of a checkout of the ``llvm-project`` git repository.
|
|
|
|
First, set variables in your shell session that will be used throughout the
|
|
build instructions:
|
|
|
|
.. code-block:: bash
|
|
|
|
SYSROOT=$HOME/sysroot-deb-arm64-stable
|
|
TARGET=aarch64-linux-gnu
|
|
CFLAGS=""
|
|
|
|
To customise details of the compilation target or choose a different
|
|
architecture altogether, change the ``SYSROOT``,
|
|
``TARGET``, and ``CFLAGS`` variables to something matching your target. For
|
|
example, for 64-bit RISC-V you might set
|
|
``SYSROOT=$HOME/sysroot-deb-riscv64-unstable``, ``TARGET=riscv64-linux-gnu``
|
|
and ``CFLAGS="-march=rva20u64"``. Refer to documentation such as your target's
|
|
compiler documentation or processor manual for guidance on which ``CFLAGS``
|
|
settings may be appropriate. The specified ``TARGET`` should match the triple
|
|
used within the sysroot (i.e. ``$SYSROOT/usr/lib/$TARGET`` should exist).
|
|
|
|
Then execute the following snippet to create a toolchain file:
|
|
|
|
.. code-block:: bash
|
|
|
|
cat - <<EOF > $TARGET-clang.cmake
|
|
set(CMAKE_SYSTEM_NAME Linux)
|
|
set(CMAKE_SYSROOT "$SYSROOT")
|
|
set(CMAKE_C_COMPILER_TARGET $TARGET)
|
|
set(CMAKE_CXX_COMPILER_TARGET $TARGET)
|
|
set(CMAKE_C_FLAGS_INIT "$CFLAGS")
|
|
set(CMAKE_CXX_FLAGS_INIT "$CFLAGS")
|
|
set(CMAKE_LINKER_TYPE LLD)
|
|
set(CMAKE_C_COMPILER clang)
|
|
set(CMAKE_CXX_COMPILER clang++)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
|
EOF
|
|
|
|
|
|
Then configure and build by invoking ``cmake``:
|
|
|
|
.. code-block:: bash
|
|
|
|
cmake -G Ninja \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DLLVM_ENABLE_PROJECTS="lld;clang" \
|
|
-DCMAKE_TOOLCHAIN_FILE=$(pwd)/$TARGET-clang.cmake \
|
|
-DLLVM_HOST_TRIPLE=$TARGET \
|
|
-DCMAKE_INSTALL_PREFIX=$HOME/clang-$TARGET \
|
|
-S llvm \
|
|
-B build/$TARGET
|
|
cmake --build build/$TARGET
|
|
|
|
These options from the toolchain file and ``cmake`` invocation above are
|
|
important:
|
|
|
|
* ``CMAKE_SYSTEM_NAME``: Perhaps surprisingly, explicitly setting this
|
|
variable `causes CMake to set
|
|
CMAKE_CROSSCOMPIILING <https://cmake.org/cmake/help/latest/variable/CMAKE_CROSSCOMPILING.html#variable:CMAKE_CROSSCOMPILING>`_.
|
|
* ``CMAKE_{C,CXX}_COMPILER_TARGET``: This will be used to set the
|
|
``--target`` argument to ``clang``. The triple should match the triple used
|
|
within the sysroot (i.e. ``$SYSROOT/usr/lib/$TARGET`` should exist).
|
|
* ``CMAKE_FIND_ROOT_PATH_MODE_*``: These `control the search behaviour for
|
|
finding libraries, includes or binaries
|
|
<https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html#finding-external-libraries-programs-and-other-files>`_.
|
|
Setting these prevents files for the host being used in the build.
|
|
* ``LLVM_HOST_TRIPLE``: Specifies the target triple of the system the built
|
|
LLVM will run on, which also implicitly sets other defaults such as
|
|
``LLVM_DEFAULT_TARGET_TRIPLE``. For example, if you are using an x86_64
|
|
host to compile for RISC-V, this will be a RISC-V triple.
|
|
* ``CMAKE_SYSROOT``: The path to the sysroot containing libraries and headers
|
|
for the target.
|
|
* ``CMAKE_INSTALL_PREFIX``: Setting this avoids installing binaries compiled
|
|
for the target system into system directories for the host system. It is
|
|
not required unless you are going to use the ``install`` target.
|
|
|
|
See `LLVM's build documentation
|
|
<https://llvm.org/docs/CMake.html#frequently-used-cmake-variables>`_ for more
|
|
guidance on CMake variables (e.g. ``LLVM_TARGETS_TO_BUILD`` may be useful if
|
|
your cross-compiled binaries only need to support compiling for one target).
|
|
|
|
Working around a ninja dependency issue
|
|
---------------------------------------
|
|
|
|
If you followed the instructions above to create a sysroot, you may run into a
|
|
`longstanding problem related to path canonicalization in ninja
|
|
<https://github.com/ninja-build/ninja/issues/1330>`_. GCC canonicalizes system
|
|
headers in dependency files, so when ninja reads them it does not need to do
|
|
so. Clang does not do this, and unfortunately ninja does not implement the
|
|
canonicalization logic at all, meaning for some system headers with symlinks
|
|
in the paths, it can incorrectly compute a non-existing path and consider it
|
|
as always modified.
|
|
|
|
If you are suffering from this issue, you will find any attempt at an
|
|
incremental build (including the suggested command to build the ``install``
|
|
target in the next section) results in recompiling everything. ``ninja -C
|
|
build/$TARGET -t deps`` shows files in ``$SYSROOT/include/*`` that
|
|
do not exist (as the ``$SYSROOT/include`` folder does not exist) and you can
|
|
further confirm these files are causing ``ninja`` to determine a rebuild is
|
|
necessary with ``ninja -C build/$TARGET -d deps``.
|
|
|
|
A workaround is to create a symlink so that the incorrect
|
|
``$SYSROOT/include/*`` dependencies resolve to files within
|
|
``$SYSROOT/usr/include/*``. This works in practice for the simple
|
|
cross-compilation use case described here, but is not a general solution.
|
|
|
|
.. code-block:: bash
|
|
|
|
sudo ln -s usr/include $SYSROOT/include
|
|
|
|
Testing the just-built compiler
|
|
-------------------------------
|
|
|
|
Confirm the ``clang`` binary was built for the expected target architecture:
|
|
|
|
.. code-block:: bash
|
|
|
|
$ file -L ./build/aarch64-linux-gnu/bin/clang
|
|
./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 stripped
|
|
|
|
If you have ``qemu-user`` installed you can test the produced target binary
|
|
either by invoking ``qemu-{target}-static`` directly:
|
|
|
|
.. code-block:: bash
|
|
|
|
$ qemu-aarch64-static -L $SYSROOT ./build/aarch64-linux-gnu/bin/clang --version
|
|
clang version 21.0.0git (https://github.com/llvm/llvm-project cedfdc6e889c5c614a953ed1f44bcb45a405f8da)
|
|
Target: aarch64-unknown-linux-gnu
|
|
Thread model: posix
|
|
InstalledDir: /home/asb/llvm-project/build/aarch64-linux-gnu/bin
|
|
|
|
Or, if binfmt_misc is configured (as was necessary for debootstrap):
|
|
|
|
.. code-block:: bash
|
|
|
|
$ export QEMU_LD_PREFIX=$SYSROOT; ./build/aarch64-linux-gnu/bin/clang --version
|
|
clang version 21.0.0git (https://github.com/llvm/llvm-project cedfdc6e889c5c614a953ed1f44bcb45a405f8da)
|
|
Target: aarch64-unknown-linux-gnu
|
|
Thread model: posix
|
|
InstalledDir: /home/asb/llvm-project/build/aarch64-linux-gnu/bin
|
|
|
|
Installing and using
|
|
--------------------
|
|
|
|
.. note::
|
|
Use of the ``install`` target requires that you have set
|
|
``CMAKE_INSTALL_PREFIX`` otherwise it will attempt to install in
|
|
directories under `/` on your host.
|
|
|
|
If you want to transfer a copy of the built compiler to another machine, you
|
|
can first install it to a location on the host via:
|
|
|
|
.. code-block:: bash
|
|
|
|
cmake --build build/$TARGET --target=install
|
|
|
|
This will install the LLVM/Clang headers, binaries, libraries, and other files
|
|
to paths within ``CMAKE_INSTALL_PREFIX``. Then tar that directory for transfer
|
|
to a device that runs the target architecture natively:
|
|
|
|
.. code-block:: bash
|
|
|
|
tar -czvf clang-$TARGET.tar.gz -C $HOME clang-$TARGET
|
|
|
|
The generated toolchain is portable, but requires compatible versions of any
|
|
shared libraries it links against. This means using a sysroot that is as
|
|
similar to your target operating system as possible is desirable. Other `CMake
|
|
variables <https://llvm.org/docs/CMake.html#frequently-used-cmake-variables>`_
|
|
may be helpful, for instance ``LLVM_STATIC_LINK_CXX_STDLIB``.
|