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>)"

    例如,//src/foo:bar(//toolchain:debug) 對應於 //src/foo/BUILD.gn 中定義的 bar 目標,當使用 //toolchain:debug 工具鍊的指令編譯時,就會對應這個目標。

  • 單獨的 GN 執行內容

    每個工具鍊執行個體都會執行自己的 GN buildconfig 檔案剖析作業,並為工具鍊中定義目標的所有規則設定全域變數和預設值。

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

  • 目標輸出的獨立根目錄

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

    此位置可透過 root_out_dir 變數在 GN 產生時間取得。

始終會有一個至少稱為預設工具鍊的工具鍊,該工具鍊會透過從 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 版本支援多種「建構變化版本」,可讓建構機器程式碼的方式略有不同,例如:

    • asanubsan 變數分別用於使用 Clang 的 Address Sanitizer 和未定義 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 編譯工具。

    這些函式可用來產生輸出內容,在一些其他工具鍊 (例如語言繫結) 中其他目標所使用的輸出,以避免重複作業。

    請注意,一個基本工具鍊用於建構 Go 二進位檔,另一個用於 Dart 二進位檔,因為 GN 完全不支援這些語言。

  • clang_toolchain() 會定義叫用 Clang 編譯器的工具鍊執行個體。支援使用 GN 內建規則建構 C++ 和 Rust 來源。

    支援的目標平台包括 Fuchsia、Linux、MacOS、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() 的差異主要是歷史事件,日後可能會合併為通用範本。