GN 工具鍊總覽
GN 建構工具可讓一個建構作業使用多個工具鍊,以不同方式編譯相同目標。
每個 toolchain() 執行個體都會對應至:
專屬名稱,以 GN 標籤表示。
舉例來說,「//build/toolchain/fuchsia:x64」會命名
//build/toolchain/fuchsia/BUILD.gn檔案中定義的工具鍊例項,並使用toolchain("x64")定義。一組用於編譯原始碼和連結二進位檔的指令和建構旗標。
舉例來說,使用一個工具鍊叫用 Clang,另一個工具鍊叫用 Microsoft Visual C++,即可讓單一建構作業使用這兩套編譯器產生二進位檔。
建構圖表節點命名空間。
使用相同 GN 路徑,但以不同工具鍊執行個體編譯的目標。這會反映在完整 GN 標籤的格式中,看起來像
"//<dir>:<target>(<toolchain_dir>:<toolchain_target>)"。舉例來說,使用
//toolchain:debug工具鍊的指令編譯時,//src/foo:bar(//toolchain:debug)會對應至//src/foo/BUILD.gn中定義的bar目標。獨立的 GN 執行環境。
每個工具鍊執行個體都會剖析 GN buildconfig 檔案,為該工具鍊中定義目標的所有規則設定全域變數和預設值。
在實務上,如果使用兩種不同的工具鍊建構相同目標,系統會剖析對應的
BUILD.gn檔案兩次,但每次都會使用一組不同的全域變數、預設設定和BUILDCONFIG.gn中定義的自訂範本。目標輸出的個別根目錄。
在預設工具鍊中建構的目標會放在
root_build_dir下方,而使用//<toolchain_dir>:<toolchain_name>執行個體建構的目標則會放在${root_build_dir}/<toolchain_name>下方。這個位置可在 GN 生成時間透過
root_out_dir變數取得。
至少會有一條工具鍊 (稱為「預設工具鍊」),這是透過從 buildconfig 檔案呼叫 set_default_toolchain()來決定。
詳情請參閱toolchain()參考說明文件。
Fuchsia 建構作業如何使用 GN 工具鍊
Fuchsia 建構作業會以多種方式使用 GN 工具鍊:
建構主機和裝置可執行檔。
目前,建構作業會定義
//build/toolchain/fuchsia:x64和//build/toolchain/fuchsia:arm64,以便為 64 位元 Intel 和 ARM 架構建構 Fuchsia 可執行二進位檔。此外,它也會定義
//build/toolchain:host_x64,為主體機器 (即建構發生的位置) 建構程式碼。此外,即使主機未執行這些架構,它也會定義
//build/toolchain:linux_x64和//build/toolchain:linux_arm64,以產生 Linux 64 位元程式碼。此外,還有許多專用工具鍊可用於編譯開機載入程式和部分核心,稍後會說明。
建構 ELF 共用程式庫。
在 Fuchsia 上,進入共用物件的機器碼 (即 GN 語言中的
shared_library()和loadable_module()執行個體) 必須使用-fPIC編譯器和連結器選項建構。這與可執行程式碼不同,可執行程式碼會改用
-fPIE。為解決這個問題,我們定義了個別的工具鍊例項,用於編譯共用程式庫的程式碼。
詳情請參閱「ELF 共用程式庫重新導向」。
建構不同變數 (例如插碼或最佳化) 的二進位檔。
Fuchsia 建構作業支援多個「建構變種版本」,可稍微不同的方式建構機器碼,例如:
asan和ubsan變體分別用於透過 Clang 的 Address Sanitizer 和 Undefined Behaviour Sanitizer 建構機器碼。甚至還有結合兩者的asan-ubsan變體。coverage變數用於建構機器碼,並啟用 Clang 的檢測式剖析功能,以支援程式碼涵蓋率收集作業。profile變體也用於建構插碼程式碼,但目的是支援設定檔引導最佳化。thinlto和lto變數用於建構二進位檔,並啟用連結時間最佳化。gcc變體用於使用 GCC 編譯器 (而非 Clang) 建構特定 Zircon 核心片段,有助於找出可能以非常重要的方式影響核心的細微機器碼產生問題。
建構作業的
BUILDCONFIG.gn檔案中也定義了許多其他變體。產生 (或處理) 來源檔案。
建構作業需要在許多地方產生原始檔,供其他目標使用。舉例來說,系統會處理 FIDL 通訊協定定義檔,為各種語言 (C++、Rust、Go 和 Dart) 產生繫結,供其他
source_set()或類似目標使用。由於使用這些來源的目標可以在不同的工具鍊執行個體中定義,因此確保這項產生作業只執行一次 (而非每個工具鍊執行個體執行一次),會很有幫助,因為在所有情況下,輸出內容都會完全相同。
因此,Fuchsia 建構會定義
fidling工具鍊,以執行 FIDL 繫結生成作業。請注意,這個工具鍊只會用於透過action()目標執行幾個指令碼,絕不會實際編譯這些指令碼。同樣地,建構作業中也定義了許多其他「基本」工具鍊,可執行不應重複的處理工作。
Fuchsia 建構作業如何定義 toolchain() 執行個體。
Fuchsia 建構作業提供這些範本,可定義具有各種功能的 toolchain() 執行個體:
basic_toolchain()定義「基本」工具鍊,也就是只以copy()或action()為目標,且永遠不需要使用 GN 內建的 C++ 和 Rust 編譯支援。這些項目用於產生輸出內容,供其他工具鍊 (例如語言繫結) 中的其他目標使用,避免重複作業。
請注意,由於 GN 完全不支援這些語言,因此會使用一個基本工具鍊來建構 Go 二進位檔,另一個則用於建構 Dart 二進位檔。
clang_toolchain()會定義叫用 Clang 編譯器的工具鍊執行個體。支援使用 GN 的內建規則建構 C++ 和 Rust 來源。支援的目標平台包括 Fuchsia、Linux、Win32 PE/COFF (UEFI 啟動載入程式需要此平台),甚至是 WebAssembly!
clang_toolchain_suite()會根據目前的建構變數設定,定義一或多個工具鍊執行個體。建議您使用這個方法,而不是直接呼叫clang_toolchain(),因為這樣才能讓建構變體正常運作。clang_host_toolchain_suite()用於產生主體機器的機器碼的工具鍊。zircon_toolchain()定義可用於建構 Zircon 核心、開機載入程式,甚至是 C 程式庫部分的工具鍊執行個體。這些二進位檔通常需要非標準的編譯和連結器指令 (例如不同的 ABI,或缺少標準連結環境)。注意:`zircon_toolchain() 建立的工具鍊不支援 Rust 程式設計語言。
這個範本的一項顯著功能是,它也支援使用 GCC 編譯器 (而非 Clang) 建構二進位檔。這項功能已證明有助於找出核心非常敏感的低階程式碼生成問題。
注意:我們不打算支援使用 GCC 建構平台其餘部分。
zircon_toolchain_suite()用於根據目前的建構變數設定,定義一或多個工具鍊執行個體。相較於直接呼叫zircon_toolchain(),建議使用這個方法。
請注意,zircon_toolchain() 和 clang_toolchain() 的區別主要是歷史因素,未來可能會合併為通用範本。