如何使用 Clang/LLVM 交叉编译 Clang/LLVM¶
简介¶
本文档包含关于在主机上构建 LLVM 和 Clang,并以另一平台为目标的信息。
有关如何使用 Clang 作为交叉编译器的更多信息,请查看 https://clang.llvm.net.cn/docs/CrossCompilation.html。
待办事项:将 MIPS 和其他平台添加到本文档。
从 x86_64 交叉编译到 ARM¶
在此用例中,我们将在基于 Debian 的 Linux 系统上使用 CMake 和 Ninja,从 x86_64 主机(目前大多数 Intel 和 AMD 芯片)交叉编译到硬浮点 ARM 目标(目前大多数 ARM 目标)。
您需要的软件包是
cmake
ninja-build
(来自 Ubuntu 的 backports)
gcc-4.7-arm-linux-gnueabihf
gcc-4.7-multilib-arm-linux-gnueabihf
binutils-arm-linux-gnueabihf
libgcc1-armhf-cross
libsfgcc1-armhf-cross
libstdc++6-armhf-cross
libstdc++6-4.7-dev-armhf-cross
配置 CMake¶
有关如何为 LLVM/Clang 配置 CMake 的更多信息,请参阅 使用 CMake 构建 LLVM。
您需要添加的 CMake 选项是
-DCMAKE_SYSTEM_NAME=<目标系统>
-DCMAKE_INSTALL_PREFIX=<安装目录>
-DLLVM_HOST_TRIPLE=arm-linux-gnueabihf
-DLLVM_TARGETS_TO_BUILD=ARM
注意:当设置 CMAKE_SYSTEM_NAME
时,CMAKE_CROSSCOMPILING
始终会自动设置。请勿在您的选项中放入 -DCMAKE_CROSSCOMPILING=TRUE
。
另请注意,LLVM_HOST_TRIPLE
指定交叉构建的 LLVM 将要运行的系统的 triple - 该标志是根据 autoconf build/host/target 命名法命名的。(此标志隐式设置其他默认值,例如 LLVM_DEFAULT_TARGET_TRIPLE
。)
如果您正在使用 GCC 进行编译,则可以使用目标的架构选项,并且编译器驱动程序将检测到它需要的一切
-DCMAKE_CXX_FLAGS='-march=armv7-a -mcpu=cortex-a9 -mfloat-abi=hard'
但是,如果您正在使用 Clang,则驱动程序可能不是最新的,与您特定的 Linux 发行版、版本或 GCC 布局不符,因此您需要进行调整。
除了上面的选项,您还需要
--target=arm-linux-gnueabihf
或者您的交叉 GCC 的 triple。
'--sysroot=/usr/arm-linux-gnueabihf'
、'--sysroot=/opt/gcc/arm-linux-gnueabihf'
或您的 GCC 的 sysroot 的位置(/lib、/bin 等所在的位置)。根据交叉 GCC 的安装方式以及库和头文件的位置,适当使用
-I
和-L
。
您可能还想设置 LLVM_NATIVE_TOOL_DIR
选项 - 指向一个包含预构建 LLVM 工具(llvm-tblgen
、clang-tblgen
等)的目录,以便在构建主机上使用,如果可用,允许您重用它们。例如 -DLLVM_NATIVE_TOOL_DIR=<path-to-native-llvm-build>/bin
。如果未设置该选项(或目录不包含所有需要的工具),则 LLVM 交叉构建将自动启动嵌套构建以构建所需的工具。
CXX 标志定义了目标、cpu(在本例中默认为带有 NEON 的 fpu=VFP3
)以及强制硬浮点 ABI。如果您正在使用 Clang 作为交叉编译器,您还必须设置 --sysroot
以确保它选择正确的链接器。
使用 Clang 时,重要的是您选择的 triple 与 GCC triple 和 sysroot 完全相同。这将使 Clang 更容易找到正确的工具和包含头文件。但这并不意味着会找到所有头文件和库。您仍然需要使用 -I
和 -L
来定位那些额外的文件,具体取决于您的发行版。
大多数时候,您想要的是拥有一个平台的原生编译器,而不是其他平台的。因此,编译所有后端几乎没有意义。因此,您还应该将 TARGETS_TO_BUILD
设置为仅构建您要针对的后端。
您必须设置 CMAKE_INSTALL_PREFIX
,否则 ninja install
会将 ARM 二进制文件复制到您的根文件系统,这不是您想要的。
技巧¶
当前的 LLVM 中存在一些错误,需要在运行 CMake 之前进行一些调整
如果您正在使用 Clang 作为交叉编译器,则 LLVM ARM 后端存在一个问题,该问题在位置无关代码 (
R_ARM_THM_MOVW_ABS_NC
) 上产生绝对重定位,因此目前,您应该禁用 PIC-DLLVM_ENABLE_PIC=False
这不是问题,因为 Clang/LLVM 库无论如何都是静态链接的,所以应该不会有太大影响。
ARM 库不会安装在您的系统中。但是 CMake 准备步骤(检查依赖项)将检查主机库,而不是目标库。下面列出了一些依赖项,但您的项目可能具有更多依赖项,或者本文档可能已过时。您将在链接时看到错误,以此作为指示。
基于 Debian 的发行版有一种添加
multiarch
的方法,该方法添加了一种新架构,并允许您为这些系统安装软件包。有关更多信息,请参见 https://wiki.debian.org/Multiarch/HOWTO。但并非所有发行版都具有该功能,并且可能没有简单的方法以任何方式安装它们,因此您必须单独构建/下载它们。
获取库的一种快速方法是从发行版存储库(如 Debian (http://packages.debian.org/jessie/))下载它们,并下载缺少的库。请注意,
libXXX
将具有共享对象 (.so
),而libXXX-dev
将为您提供头文件和静态 (.a
) 库。为了以防万一,请同时下载两者。您为 ARM 需要的是:
libtinfo
、zlib1g
、libxml2
和liblzma
。在 Debian 存储库中,您将找到所有架构的下载。下载并解压缩所有
.deb
软件包后,将所有.so
和.a
复制到一个目录,创建适当的符号链接(如果需要),并将相关的-L
和-I
路径添加到上面的-DCMAKE_CXX_FLAGS
中。
运行 CMake 和构建¶
最后,如果您正在使用您的平台编译器,请运行
$ cmake -G Ninja <source-dir> -DCMAKE_BUILD_TYPE=<type> <options above>
如果您正在使用 Clang 作为交叉编译器,请运行
$ CC='clang' CXX='clang++' cmake -G Ninja <source-dir> -DCMAKE_BUILD_TYPE=<type> <options above>
如果您的路径中有 clang
/clang++
,它应该可以正常工作,并且特殊的 Ninja 文件将在构建目录中创建。我强烈建议您在单独的构建目录中运行 cmake
,而不是在源代码树内部。
要构建,只需键入
$ ninja
它应该会自动找出您有多少个核心,哪些是需要构建的规则,并将构建整个内容。
您不能在此树上运行 ninja check-all
,因为创建的二进制文件是针对 ARM 而不是 x86_64 的。
安装和使用¶
在 LLVM/Clang 成功构建后,您应该通过以下方式安装它
$ ninja install
这将在 install-dir 上创建一个 sysroot。然后,您可以将该目录压缩到一个具有完整 triple 名称的二进制文件中(为了便于识别),例如
$ ln -sf <install-dir> arm-linux-gnueabihf-clang $ tar zchf arm-linux-gnueabihf-clang.tar.gz arm-linux-gnueabihf-clang
例如,如果您将该 tarball 复制到您的目标板,您将能够使用它来运行测试套件。请遵循 https://llvm.net.cn/docs/lnt/quickstart.html 上的指南,在测试目录中解压缩 tarball,并使用选项
$ ./sandbox/bin/python sandbox/bin/lnt runtest nt \ --sandbox sandbox \ --test-suite `pwd`/test-suite \ --cc `pwd`/arm-linux-gnueabihf-clang/bin/clang \ --cxx `pwd`/arm-linux-gnueabihf-clang/bin/clang++
记住将 -jN
选项添加到 lnt
中,以匹配您板上的 CPU 数量。此外,您的 clang 路径必须是绝对路径,因此您需要上面提到的 pwd 技巧。