使用 Clang/LLVM 交叉編譯 Clang/LLVM¶
簡介¶
本文檔包含在主機上構建針對另一個平台的 LLVM 和 Clang 的資訊。
有關如何將 Clang 用作交叉編譯器的更多資訊,請查看 https://clang.llvm.org/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 的系統的三元組 - 該標誌是根據 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 等所在的位置)的位置。適當使用
-I
和-L
,具體取決於交叉 GCC 的安裝方式以及函式庫和標頭檔的位置。
您可能還想設定 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 時,選擇與 GCC 三元組和系統根目錄相同的目標三元組非常重要。這將使 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
如果您將該壓縮檔複製到目標板,您就可以使用它來執行測試套件,例如,請遵循 https://llvm.dev.org.tw/docs/lnt/quickstart.html 的指南,在測試目錄中解壓縮壓縮檔,並使用以下選項
$ ./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
中,其中 N 是您板子上 CPU 的數量。此外,clang 的路徑必須是絕對路徑,因此您需要使用上面提到的 pwd 技巧。