如何使用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主机(如今大多数英特尔和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将在其上运行的系统的三元组 - 该标志的命名基于autoconf的构建/主机/目标命名法。(此标志隐式设置其他默认值,例如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的三元组。
'--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(在本例中默认为fpu=VFP3
以及NEON),并强制使用硬浮点ABI。如果您使用Clang作为交叉编译器,则还必须设置--sysroot
以确保它选择正确的链接器。
使用Clang时,重要的是您选择的三元组必须与GCC三元组和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
这将在安装目录中创建一个sysroot。然后,您可以将该目录打包成一个带有完整三元组名称(以便于识别)的二进制文件,例如:
$ 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技巧。