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 社群維護的官方 monorepo:
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
您需要 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}
Linux 的 Sysroot
如要納入 Linux 適用的編譯器執行階段和 C++ 程式庫,請下載 sysroot。必須位於 ${SYSROOT_DIR} 變數指向的目錄中。
SYSROOT_DIR=${FUCHSIA_DIR}/prebuilt/third_party/sysroot
為 Fuchsia 建構 Clang 工具鍊
Clang CMake 建構系統支援啟動程序 (又稱多階段) 建構。Fuchsia 會使用 兩階段啟動建構作業,建構 Clang 編譯器。不過,如果是與工具鍊相關的開發作業,建議使用單一階段建構。
如果您的目標是實驗 clang,單階段建構可能就是您要的。第一階段編譯器是僅限主機的編譯器,其中設定了第二階段所需的選項。第二階段編譯器是經過全面最佳化的編譯器,可提供給使用者。
設定這些編譯器需要許多選項。為簡化設定,Fuchsia Clang 建構設定會包含在 CMake 快取檔案中,這些檔案是 Clang 程式碼集 (Fuchsia.cmake 和 Fuchsia-stage2.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 \
-DLLVM_ENABLE_LTO=OFF \
-DLINUX_x86_64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/linux \
-DLINUX_aarch64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/linux \
-DLINUX_riscv64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/ubuntu20.04 \
-DLINUX_armv7-unknown-linux-gnueabihf_SYSROOT=${SYSROOT_DIR}/linux \
-DLINUX_i386-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/linux \
-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 相關,您可能需要在 PATH 中新增 ninja。您可以在 ${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 \
-DCMAKE_INSTALL_PREFIX= \
-DSTAGE2_LINUX_x86_64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/linux \
-DSTAGE2_LINUX_aarch64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/linux \
-DSTAGE2_LINUX_riscv64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/ubuntu20.04 \
-DSTAGE2_LINUX_armv7-unknown-linux-gnueabihf_SYSROOT=${SYSROOT_DIR}/linux \
-DSTAGE2_LINUX_i386-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/linux \
-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=${FUCHSIA_DIR}/prebuilt/third_party/sysroot
CLANG_TOOLCHAIN_PREFIX=${FUCHSIA_DIR}/prebuilt/third_party/clang/linux-x64/bin/
# Download necessary dependencies
cipd install fuchsia/sdk/core/linux-amd64 latest -root ${IDK_DIR}
# CMake invocation
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_TOOLCHAIN_FILE=${FUCHSIA_DIR}/scripts/clang/ToolChain.cmake \
-DLLVM_ENABLE_LTO=OFF \
-DLINUX_x86_64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/linux \
-DLINUX_aarch64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/linux \
-DLINUX_riscv64-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/ubuntu20.04 \
-DLINUX_armv7-unknown-linux-gnueabihf_SYSROOT=${SYSROOT_DIR}/linux \
-DLINUX_i386-unknown-linux-gnu_SYSROOT=${SYSROOT_DIR}/linux \
-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\" 傳遞至 fx set 指令,然後執行 fx build。
fx set core.x64 --args=clang_prefix=\"${INSTALL_DIR}/bin\"
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" \
CMake 快取檔案中已設定 LLVM_ENABLE_PROJECTS 和 LLVM_ENABLE_RUNTIMES,因此您通常不需要設定這些項目,除非您想明確新增更多專案或執行階段。
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/
消毒劑
只要在 cmake 呼叫中加入 LLVM_USE_SANITIZER=<sanitizer name>,即可在 LLVM 工具上使用大多數清除器。不過,由於部分 LLVM 工具會觸發誤判,因此 MSan 較為特殊。如要建構支援 MSan 的項目,請先建構支援 MSan 的 libc++。您可以在同一個版本中執行這項操作。如要設定支援 MSan 的建構作業,請先執行 CMake,並使用 LLVM_USE_SANITIZER=Memory 和 LLVM_ENABLE_LIBCXX=ON。
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 建構工具會將所有建構成果上傳至內容定址儲存空間 (CAS)。這個工具可讓您快速下載特定工具鍊,不必從頭建構。這樣一來,您就能避免長時間建構 LLVM 和 Fuchsia,大幅加快工具鍊問題的調查速度。
以下範例說明如何從頭安裝 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 工具會使用該 ID 擷取正確的構件。
如要取得 digest,請前往 Fuchsia 的 CI 建構工具,選取要取得工具鍊的建構工具,然後依序展開 clang->cas->archive 欄位,再點選 CAS_UI 連結。
結果頁面會顯示 CAS 上傳作業的相關資訊,包括摘要。
實用的 CMake 標記
還有許多其他 CMake 旗標可用於建構作業,但這些旗標可能適用於建構工具鍊。
-DLLVM_PARALLEL_LINK_JOBS
增加可平行執行的連結工作數量 (在本機)。連結工作數量取決於 RAM 大小。如果是 LTO 建構作業,每個工作至少需要 10 GB。
其他資源
說明文件:
演講: