如何在 x64 主机上为 AArch64 交叉编译 LLVM/Clang?

How do I cross-compile LLVM/Clang for AArch64 on x64 host?

我想在我的 AArch64 上使用 clang-11 Raspberry Pi 4,运行 Ubuntu 20.04 Focal。我查看了 https://apt.llvm.org/,但 AArch64 预构建二进制文件似乎不可用?

我尝试直接在 Raspberry Pi 上构建 clang,但它非常慢,我最终 运行 出了 SD 卡上的 space。

如何在我的 x64 笔记本电脑上自己交叉编译 clang?

构建 LLVM 可能会很棘手,因为它需要大量的计算资源,这使得很难使用不同的构建选项进行迭代。我第一次尝试为我的 AArch64 Raspberry PI 构建 t运行k 版本的 clang 最终得到了一个 ARM7 的构建,而且大小也是 30GB,这不适合存储卡。哎呀

在项目 wiki 上学习文档

第一个相关的 Clang 文档页面是 Building LLVM with CMake。它解释了 CMake 选项 CMAKE_BUILD_TYPECMAKE_INSTALL_PREFIXLLVM_TARGETS_TO_BUILD.

最好设置 -DCMAKE_BUILD_TYPE=MinSizeRel 或默认值 Debug 以外的其他值。 clang 的调试构建将 运行 显着变慢。自定义 CMAKE_INSTALL_PREFIX 是必要的,因为您不想将 Clang 安装到您的主机系统上。给它 -DCMAKE_INSTALL_PREFIX=$PWD/install,然后将安装目录复制到你的 AArch64 机器上。

要减小安装的大小,请设置 -DLLVM_TARGETS_TO_BUILD=AArch64。默认是构建所有目标。

启用断言

如果你想使用尖端功能,这很可能,否则,为什么要编译 clang,你会希望在 clang 代码中启用断言,并且你会需要调试符号。它会减慢程序速度并使其变大,但由于提高了安全性和可调试性,因此绝对值得。在这种情况下查看 Getting the Source Code and Building LLVM 并设置 -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLLVM_ENABLE_ASSERTIONS=On

接下来,阅读 Building a Distribution of LLVM。相关建议是通过设置 -DLLVM_BUILD_LLVM_DYLIB=On -DLLVM_LINK_LLVM_DYLIB=On -DLLVM_INSTALL_TOOLCHAIN_ONLY=On.

进一步最小化安装大小

最后,阅读How To Cross-Compile Clang/LLVM using Clang/LLVM。即使您计划使用 GCC 进行交叉编译,此页面也很有帮助。如果您正在使用 Ubuntu Focal,无论是直接使用还是在 Docker 容器中构建,您最终可能会得到 CMake 命令的骨架,例如

CC=aarch64-linux-gnu-gcc-10 CXX=aarch64-linux-gnu-g++-10 cmake ../llvm \
  -DCMAKE_CROSSCOMPILING=True \
  -DLLVM_TARGET_ARCH=AArch64 \
  -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-linux-gnueabihf \
  -DCMAKE_CXX_FLAGS='-march=armv8-a -mtune=cortex-a72' \
  -GNinja

那里的选项应该很简单,除了 LLVM_TABLEGENCLANG_TABLEGEN。必须指定它们,因为这些二进制文件需要在主机上 运行,但是构建会为目标编译它们,因此它不能使用它刚刚构建的内容。现有二进制文件必须由您提供。虽然 llvm-tblgen 可以与 llvm 包一起安装,但 clang-tblgen 不是发行版的一部分。这意味着,您需要进行两次构建。首先,为主机构建这两个二进制文件(您不必构建完整的 LLVM,这两个二进制文件就足够了),然后将交叉编译指向它们。

mkdir build-host
cd build-host
CC=gcc-10 CXX=g++-10 cmake ../llvm -DLLVM_ENABLE_PROJECTS='clang;compiler-rt;lld;clang-tools-extra' -GNinja
ninja llvm-tblgen clang-tblgen

现在,在你的交叉构建中使用这些二进制文件,所以添加到你的 CMake 命令中

-DLLVM_TABLEGEN=/usr/bin/llvm-tblgen-11 -DCLANG_TABLEGEN=/mnt/repos/llvm-project/build-host/bin/clang-tblgen

开始docker

建议将包含 llvm 源的目录从文件系统挂载到容器中。这将使编译结果更容易输出,而且本机文件系统比 docker.

中的覆盖更快
docker run -v `pwd`:/mnt --rm -it ubuntu:focal bash

安装依赖项

在 Ubuntu 20.04 焦点

apt install g++-10-aarch64-linux-gnu libstdc++-10-dev-arm64-cross gcc-10 g++-10
apt install cmake ninja-build python3

配置

mkdir build-aarch64
cd build-aarch64

CC=aarch64-linux-gnu-gcc-10 CXX=aarch64-linux-gnu-g++-10 cmake ../llvm \
    -DCMAKE_BUILD_TYPE=RelWithDebInfo \
    -DLLVM_ENABLE_ASSERTIONS=On \
    -DCMAKE_CROSSCOMPILING=True \
    -DCMAKE_INSTALL_PREFIX=install \
    -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-linux-gnueabihf \
    -DLLVM_TARGET_ARCH=AArch64 \
    -DLLVM_TARGETS_TO_BUILD=AArch64 \
    -DCMAKE_CXX_FLAGS='-march=armv8-a -mtune=cortex-a72' \
    -GNinja \
    -DLLVM_ENABLE_PROJECTS='clang;compiler-rt;lld;clang-tools-extra' \
    -DLLVM_TABLEGEN=/mnt/repos/llvm-project/build-host/bin/llvm-tblgen \
    -DCLANG_TABLEGEN=/mnt/repos/llvm-project/build-host/bin/clang-tblgen \
    -DLLVM_BUILD_LLVM_DYLIB=On \
    -DLLVM_LINK_LLVM_DYLIB=On \
    -DLLVM_INSTALL_TOOLCHAIN_ONLY=On

编译

如果可以的话,获得一台强大的构建机器。链接一些二进制文件需要大量 RAM。您应该有大约 20 GB 的可用内存,以便能够在合理的时间内到达任何地方,64 GB 会更好。如果碰巧多个链接任务 运行 并行耗尽了您的机器内存,请尝试使用 ninja -j3 左右进行编译,以将并行任务的数量限制为例如 3.

ninja install -j3

使用不同的链接器应该可以减少内存需求。据推测,ld.gold 在链接时对内存的要求较低。