如何使用 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 等所在位置)。根據交叉 GCC 的安裝方式以及程式庫和標頭檔的位置,適當使用
-I
和-L
。
您可能還想設定 LLVM_NATIVE_TOOL_DIR
選項 - 指向包含用於建置主機的預先建置 LLVM 工具(llvm-tblgen
、clang-tblgen
等)的目錄,以便您在可用時重複使用它們。例如,-DLLVM_NATIVE_TOOL_DIR=<原生-llvm-建置路徑>/bin
。如果未設定此選項(或目錄不包含所有需要的工具),則 LLVM 交叉建置將自動啟動巢狀建置以建置所需的工具。
CXX 標誌定義了目標、CPU(在本例中預設為帶有 NEON 的 fpu=VFP3
)以及強制硬體浮點 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.dev.org.tw/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++
請記住在 lnt
中為您的板上的 CPU 數量添加 -jN
選項。此外,您的 clang 路徑必須是絕對路徑,因此您需要上面提到的 pwd 技巧。