Fuchsia 將 Clang 做為官方編譯器。
必要條件
您需要 CMake 3.13.4 以上版本才能執行這些指令。這是建構 LLVM 的最低版本。
雖然 CMake 支援不同的建構系統,但建議使用 Ninja。
您在 Fuchsia 結帳時,兩者都必須以預建的形式提供。下列指令假設 cmake
和 ninja
位於您的 PATH
中:
export PATH=${FUCHSIA_DIR}/prebuilt/third_party/cmake/${platform}/bin:${PATH}
export PATH=${FUCHSIA_DIR}/prebuilt/third_party/ninja/${platform}/bin:${PATH}
其中 ${FUCHSIA_DIR}
是指 Fuchsia 來源樹狀結構的根目錄。
正在取得來源
下列範例指令使用 ${LLVM_SRCDIR}
來參照 LLVM 來源樹狀結構結帳的根層級。您可以使用由 LLVM 社群維護的官方單一存放區 https://github.com/llvm/llvm-project:
LLVM_SRCDIR=${HOME}/llvm/llvm-project
git clone https://github.com/llvm/llvm-project ${LLVM_SRCDIR}
cd ${LLVM_SRCDIR}
git checkout ${REVISON_NUMBER}
紫紅色
建構隨工具鍊建構的執行階段程式庫之前,您需要具備 Fuchsia IDK (舊稱 SDK)。IDK 必須位於 ${IDK_DIR}
變數指向的目錄中:
IDK_DIR=${HOME}/fuchsia-idk
如要下載最新的 IDK,您可以使用下列程式碼:
# For Linux
cipd install fuchsia/sdk/core/linux-amd64 latest -root ${IDK_DIR}
# For macOS
cipd install fuchsia/sdk/core/mac-amd64 latest -root ${IDK_DIR}
為 Fuchsia IDK 產生 RISC-V 程式庫和 Sysroot
如要為 Fuchsia 建構 RISC-V LLVM 執行階段程式庫,您需要為 Fuchsia IDK 產生 RISC-V 程式庫和 sysroot。
由於指令碼會變更 ${IDK_DIR}/pkg/sysroot/meta.json
的內容,因此我們需要將這個檔案設為可寫入:
chmod 644 "${IDK_DIR}/pkg/sysroot/meta.json"
下一步是執行指令碼,產生 RISC-V 程式庫和 sysroot:
python3 ${FUCHSIA_DIR}/scripts/clang/generate_sysroot.py --sdk-dir=${IDK_DIR} \
--arch=riscv64 \
--ifs-path=${FUCHSIA_DIR}/prebuilt/third_party/clang/${platform}/bin/llvm-ifs
若為 Linux x64 平台,${platform}
應為 linux-x64
,而在 Mac x64 平台上,則 ${platform}
應為 mac-x64
。
Linux 適用的 Sysroot
如要加入 Linux 適用的編譯器執行階段和 C++ 程式庫,請下載 sysroot。
這個檔案必須位於 ${SYSROOT_DIR}
變數指向的目錄中。
SYSROOT_DIR=${HOME}/fuchsia-sysroot/
如要下載 sysroot,可使用以下程式碼:
cipd install fuchsia/third_party/sysroot/linux integration -root ${SYSROOT_DIR}
建構適用於 Fuchsia 的 Clang 工具鍊
Clang CMake 建構系統支援啟動 (又稱為多階段) 版本。Fuchsia 針對 Clang 編譯器使用雙階段 Bootstrap 版本。不過,對於工具鍊相關的開發,建議使用單一階段建構。
如果您的目標是使用 Clang 進行實驗,那麼單一階段版本應可滿足您的需求。第一個階段編譯器是僅限主機的編譯器,具有第二階段所需的部分選項集。第二階段編譯器是全面最佳化的編譯器,目的是向使用者提供。
設定這些編譯器需要許多選項。為了簡化 Fuchsia Clang 建構設定,包含在 Clang 程式碼集 (Fuchsia.cmake
和 Fuchsia-stage2.cmake
) 的 CMake 快取檔案中。
mkdir llvm-build
mkdir llvm-install # For placing stripped binaries here
INSTALL_DIR=${pwd}/llvm-install
cd llvm-build
單一階段建構 Fuchsia 設定
開發 Fuchsia 的 Clang 時,您可以使用快取檔案測試 Fuchsia 設定,但只在啟用 LTO 的情況下執行第二個階段,如此一來,建構時間會比用於漸進式開發作業更快,因此您不必手動指定所有選項:
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_TOOLCHAIN_FILE=${FUCHSIA_DIR}/scripts/clang/ToolChain.cmake \
-DUSE_GOMA=ON \
-DLLVM_ENABLE_LTO=OFF \
-DLINUX_x86_64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR} \
-DLINUX_aarch64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR} \
-DFUCHSIA_SDK=${IDK_DIR} \
-DCMAKE_INSTALL_PREFIX= \
-C ${LLVM_SRCDIR}/clang/cmake/caches/Fuchsia-stage2.cmake \
${LLVM_SRCDIR}/llvm
ninja toolchain-distribution -j1000 # Build the distribution
如果上述方法因出現與 Ninja 相關的錯誤而失敗,您可能需要將 ninja
新增至 PATH。您可以在 ${FUCHSIA_DIR}//prebuilt/third_party/ninja/${platform}/bin
找到預先建構的執行檔。
ninja toolchain-distribution
應足以建構所有二進位檔,但 Fuchsia 版本會假設部分程式庫遭到移除,因此需要使用 ninja
install-toolchain-distribution-stripped
。
雙階段建構 Fuchsia 設定
這大致上與在實際工作環境建構工具中執行的內容相同,且用於建構 Fuchsia 運送給使用者的工具鍊。
cmake -GNinja \
-DCMAKE_TOOLCHAIN_FILE=${FUCHSIA_DIR}/scripts/clang/ToolChain.cmake \
-DUSE_GOMA=ON \
-DCMAKE_INSTALL_PREFIX= \
-DSTAGE2_LINUX_aarch64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR} \
-DSTAGE2_LINUX_x86_64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR} \
-DSTAGE2_FUCHSIA_SDK=${IDK_DIR} \
-C ${LLVM_SRCDIR}/clang/cmake/caches/Fuchsia.cmake \
${LLVM_SRCDIR}/llvm
ninja stage2-toolchain-distribution -j1000
DESTDIR=${INSTALL_DIR} ninja stage2-install-toolchain-distribution-stripped -j1000
Runtime.json
如果 Fuchsia 建構作業因缺少 runtime.json
檔案而失敗,您必須執行下列指令產生新的 runtime.json
檔案:
python3 ${FUCHSIA_DIR}/scripts/clang/generate_runtimes.py \
--clang-prefix ${INSTALL_DIR} --sdk-dir ${IDK_DIR} \
--build-id-dir ${INSTALL_DIR}/lib/.build-id > ${INSTALL_DIR}/lib/runtime.json
產生的檔案含有 Fuchsia 版本用於瞭解工具鍊各項程式庫的相對路徑。
要點總整理
用於建構單一階段工具鍊的複製貼上程式碼。這個程式碼可在 LLVM 建構目錄中執行,並假設為 Linux 環境。
cd ${LLVM_BUILD_DIR} # The directory your toolchain will be installed in
# Environment setup
FUCHSIA_DIR=${HOME}/fuchsia/ # Replace with wherever Fuchsia lives
LLVM_SRCDIR=${HOME}/llvm/llvm-project # Replace with wherever llvm-project lives
IDK_DIR=${HOME}/fuchsia-idk/
SYSROOT_DIR=${HOME}/fuchsia-sysroot/
CLANG_TOOLCHAIN_PREFIX=${FUCHSIA_DIR}/prebuilt/third_party/clang/linux-x64/bin/
GOMA_DIR=${FUCHSIA_DIR}/prebuilt/third_party/goma/linux-x64/
# Download necessary dependencies
cipd install fuchsia/sdk/core/linux-amd64 latest -root ${IDK_DIR}
cipd install fuchsia/third_party/sysroot/linux integration -root ${SYSROOT_DIR}
# CMake invocation
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE=${FUCHSIA_DIR}/scripts/clang/ToolChain.cmake \
-DUSE_GOMA=ON \
-DLLVM_ENABLE_LTO=OFF \
-DLINUX_x86_64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR} \
-DLINUX_aarch64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR} \
-DFUCHSIA_SDK=${IDK_DIR} \
-DCMAKE_INSTALL_PREFIX= \
-C ${LLVM_SRCDIR}/clang/cmake/caches/Fuchsia-stage2.cmake \
${LLVM_SRCDIR}/llvm
# Build and strip binaries and place them in the install directory
ninja toolchain-distribution -j1000
DESTDIR=${INSTALL_DIR} ninja install-toolchain-distribution-stripped -j1000
# Generate runtime.json
python3 ${FUCHSIA_DIR}/scripts/clang/generate_runtimes.py \
--clang-prefix ${INSTALL_DIR} --sdk-dir ${IDK_DIR} \
--build-id-dir ${INSTALL_DIR}/lib/.build-id > ${INSTALL_DIR}/lib/runtime.json
使用自訂 Clang 建構 Fuchsia
如要指定用於建構 Fuchsia 的自訂 clang 工具鍊,請將 --args clang_prefix=\"${INSTALL_DIR}/bin\" --no-goma
傳遞至 fx set
指令,然後執行 fx build
。
fx set core.x64 --args=clang_prefix=\"${INSTALL_DIR}/bin\" --no-goma
fx build
這個檔案包含 Fuchsia 版本用於瞭解工具鍊各程式庫所在位置的相對路徑。
開發 Clang
開發 Clang 時,您可能會想要使用更適合用於漸進式開發及快速處理時間的設定。
建構 LLVM 最簡單的方式就是使用下列指令:
cmake -GNinja \
-DCMAKE_BUILD_TYPE=Debug \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld" \
${LLVM_SRCDIR}/llvm
ninja
您可以使用 LLVM_ENABLE_PROJECTS
變數啟用其他專案。如要啟用所有常見專案,您會使用:
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;compiler-rt;libcxx;libcxxabi;libunwind"
同樣地,您也可以讓某些專案以執行階段的形式建構,這表示這些專案將使用剛剛建構的程式,而非主機編譯器:
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld" \
-DLLVM_ENABLE_RUNTIMES="compiler-rt;libcxx;libcxxabi;libunwind" \
LLVM_ENABLE_PROJECTS
和 LLVM_ENABLE_RUNTIMES
都已在 CMake 快取檔案中設定,因此除非您要明確新增更多專案或執行階段,否則通常不需要設定這些項目。
Clang 是大型專案,編譯器的效能也十分重要。如要縮短建構時間,建議使用 Clang 做為主機編譯器。如果可以,請將 LLD 做為主機連接器使用。建議使用 LTO 建構,如要達到最佳效能,也可使用設定檔引導最佳化 (PGO) 功能。
如要將主機編譯器設為 Clang,並將主機連接器設為 LLD,您可以使用下列額外標記:
-DCMAKE_C_COMPILER=${CLANG_TOOLCHAIN_PREFIX}clang \
-DCMAKE_CXX_COMPILER=${CLANG_TOOLCHAIN_PREFIX}clang++ \
-DLLVM_ENABLE_LLD=ON
這項操作假設 ${CLANG_TOOLCHAIN_PREFIX}
會指向 Clang 安裝項目的 bin
目錄,並在結尾加上斜線 (因為這個 Make 變數用於 Zircon 版本)。例如,如要使用 Fuchsia 結帳 (Linux) 中的編譯器:
CLANG_TOOLCHAIN_PREFIX=${FUCHSIA_DIR}/prebuilt/third_party/clang/linux-x64/bin/
消毒液
只要將 LLVM_USE_SANITIZER=<sanitizer name>
新增至 CMake 叫用,即可將大部分的清理程式用於 LLVM 工具。不過有些 LLVM 工具會觸發誤判情形
因此 MSan 很特別如要使用 MSan 支援進行建構,您必須先透過 MSan 支援建構 libc++。您可以在同一個版本中執行此操作。如要設定採用 MSan 支援的建構,請先使用 LLVM_USE_SANITIZER=Memory
和 LLVM_ENABLE_LIBCXX=ON
執行 CMake。
cmake -GNinja \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_COMPILER=${CLANG_TOOLCHAIN_PREFIX}clang \
-DCMAKE_CXX_COMPILER=${CLANG_TOOLCHAIN_PREFIX}clang++ \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;libcxx;libcxxabi;libunwind" \
-DLLVM_USE_SANITIZER=Memory \
-DLLVM_ENABLE_LIBCXX=ON \
-DLLVM_ENABLE_LLD=ON \
${LLVM_SRCDIR}/llvm
您通常將會執行 Ninja,但我們希望使用經淨化的 libc++ 版本建構所有內容,但如果現在建構,系統會使用來自 ${CLANG_TOOLCHAIN_PREFIX}
的 libc++,而未經淨化。所以我們先只建構 cxx 和 cxxabi 目標。當工具以動態方式連結至 libcxx 時,這些變數會用於取代 ${CLANG_TOOLCHAIN_PREFIX}
中的這些項目
ninja cxx cxxabi
現在您有了經過處理的 libc++ 版本,您可以將建構設定為使用這個版本,而非使用 ${CLANG_TOOLCHAIN_PREFIX}
中的版本,然後建構所有內容。
ninja
總結:
cmake -GNinja \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_COMPILER=${CLANG_TOOLCHAIN_PREFIX}clang \
-DCMAKE_CXX_COMPILER=${CLANG_TOOLCHAIN_PREFIX}clang++ \
-DLLVM_USE_SANITIZER=Address \
-DLLVM_ENABLE_LIBCXX=ON \
-DLLVM_ENABLE_LLD=ON \
${LLVM_SRCDIR}/llvm
ninja libcxx libcxxabi
ninja
測試 Clang
如要執行 Clang 測試,您可以使用 check-<component>
目標:
ninja check-llvm check-clang
所有測試都可以使用 check-all
執行,但請注意,這項作業可能需要大量時間,視您在建構作業中啟用的專案數量而定。
如果只要測試一項特定測試,您可以使用環境變數 LIT_FILTER
。如果測試路徑為 clang/test/subpath/testname.cpp
,您可以使用:
LIT_FILTER=testname.cpp ninja check-clang
指定不同的 check-<component>
,同樣也能以相同的技巧執行其他子專案的測試。
從 CAS 下載工具鍊
我們的 Clang Toolchain CI 建構工具會將所有建構構件上傳至內容 Addressed Storage (CAS)。這可讓您輕鬆快速下載特定工具鍊,而不必從頭開始建立。這可以大幅加快工具鍊問題的調查速度,因為除了建構 Fuchsia 之外,LLVM 的建構時間也可以縮短。
以下範例說明如何從頭開始安裝 cas
工具,並將特定工具鍊下載至語料庫目錄中:
$ cipd install infra/tools/luci/cas/linux-amd64 latest -root luci
$ ./luci/cas download -cas-instance chromium-swarm -digest \
ad53e1f315a849955190594fde6b07e11e76b40563db5779fcc69d6a6e04dc71/267 -dir corpus
在上述範例中,-digest
欄位會傳遞專屬 ID,供 cas
工具用於擷取正確的構件。您可以從 Fuchsia 的 CI 建構工具取得 digest
,方法是選取要取得工具鍊的來源建構工具,接著展開 clang
->cas
->archive
欄位,然後按一下 CAS_UI
連結。
畫面上隨即會顯示 CAS 上傳作業的一些相關資訊,包括摘要。
實用的 CMake 旗標
還有許多其他 CMake 旗標可用於建構,但其中一些對於建構工具鍊可能相當實用。
-DLLVM_PARALLEL_LINK_JOBS
增加可同時 (本機) 執行的連結工作數量。連結工作數量取決於 RAM 大小。如果是 LTO 版本,每項工作至少需要 10 GB。
其他資源
說明文件:
談話:
- 2016 年 LLVM 開發人員會議:C. Bieneman 的《Developing and Shipping LLVM and Clang with CMake》(使用 CMake 開發及運送 LLVM 和 Clang)
- 2017 年 LLVM 開發人員會議:Petr Hosek「使用 CMake 和執行階段版本編譯跨工具鍊」