GN 工具鍊和 Fuchsia Build

GN 工具鍊總覽

GN 建構工具可讓一個版本使用多個「工具鍊」,以不同的方式編譯相同的目標。

每個 toolchain() 執行個體會對應下列項目:

  • 專屬名稱,以 GN 標籤表示。

    例如,「//build/toolchain/fuchsia:x64」使用 toolchain("x64") 定義為 //build/toolchain/fuchsia/BUILD.gn 檔案中定義的工具鍊執行個體命名。

  • 一組用於編譯原始碼和連結二進位檔的指令和建構標記

    舉例來說,使用一個工具鍊叫用 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 建構設定檔剖析,針對該工具鍊中所有定義目標的規則,設定全域變數和預設值。

    實際上,如果使用兩個不同的工具鍊建構同一個目標,系統會剖析相對應的 BUILD.gn 檔案兩次,但每次使用一組不同的全域變數、預設設定和 BUILDCONFIG.gn 中定義的自訂範本。

  • 目標輸出的單獨根目錄

    雖然預設工具鍊建構的目標位於 root_build_dir 底下,但使用 //<toolchain_dir>:<toolchain_name> 執行個體建構的目標會改放在 ${root_build_dir}/<toolchain_name> 底下。

    這個位置可透過 root_out_dir 變數在 GN 產生期間使用。

一直都有至少一個稱為「預設工具鍊」的工具鍊,這會透過建構設定檔呼叫 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 的可執行程式碼不同。

    為了處理這種情況,需定義不同的工具鍊執行個體來編譯共用 librarie 的程式碼。

    詳情請參閱「ELF 共用資料庫重新導向」。

  • 建立二進位檔的不同變化版本 (例如檢測或最佳化)

    Fuchsia 版本支援多種「建構變化版本」,能以略有不同方式建構機器碼,例如:

    • asanubsan 變體分別用於建構機器程式碼,同時使用 Clang 的 Address Sanitizer,以及 Undefined Behaviour Sanitizer。甚至有 asan-ubsan 變化版本同時結合了這兩種變數。

    • coverage 變化版本可用於建構機器程式碼,並啟用 Clang 的檢測型剖析功能,以支援程式碼涵蓋率收集功能。

    • profile 變化版本也可用來建構檢測程式碼,但支援設定檔引導最佳化功能。

    • thinltolto 變化版本可用來建構啟用連結時間最佳化功能的二進位檔。

    • 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() 大多是之前的差異,未來可能會合併為通用範本。