Fuchsia 建構系統:變化版本

Fuchsia GN 建構機制可讓您在不同「變體」中建構個別元件。變體通常只是指使用額外的編譯器選項,但如果您編寫更多 GN 程式碼,變體就能執行更多作業。目前定義的變體可啟用清除器LTO 等功能。

指定變體

變數規格會透過 GN 建構引數 select_variant 傳遞至建構作業。請注意,這些變體選取器的順序很重要,詳情請參閱下方的語法一節。

使用 fx set,透過 --variant= 標記傳遞字串變數選取器:

fx set core.x64 --variant=asan/cat --variant=asan/ledger --variant=host_asan

這個範例會指示建構系統編譯「cat」和「ledger」Fuchsia 二進位檔,以及所有主機工具,並使用位址清除器 (請參閱下文,瞭解這些字串的確切語法)。

如果已有建構目錄,可以直接編輯 GN args 來新增或修改變體 (視需要將建構的 GN 輸出目錄替換為 out/default):

fx gn args out/default

該指令會開啟編輯器。在該檔案中附加一行,將變體選取器指派為 select_variant 建構引數的字串清單:

select_variant = [ "asan/cat", "asan/ledger", "host_asan" ]

選取器語法

通常你會使用一組字串做為變體選取器。每個定義都會指定變體名稱,並視需要指定適用對象。系統會依您指定的順序測試選取器,並套用第一個相符的選取器。

  • 如要全域套用具名變體,請單獨使用變體名稱,例如 asanhost_ubsan。這些全域選取器應列在最後。

  • 使用 variant_name/target_output_name 形式 (例如 asan-ubsan/ledgerhost_asan/zxdb_tests),將具名變體套用至特定目標。這些項目應列在全域選取器之前,以覆寫較一般的規則。

變體會與二進位檔 (例如 executableloadable_moduletestfuchsia_driver) 比對,而不是 Fuchsia 套件、Fuchsia 元件、共用程式庫、靜態程式庫或來源集。變體與目標相符後,系統會使用該變體編譯變體依附的所有程式庫。由於 Fuchsia 套件和元件與變體選取無關,因此在變體規格中指定套件或元件名稱不會有任何影響。套件中的每個可執行檔或模組都可以指定自己的變體。

根據預設,目標輸出名稱是您提供給 GN 目標定義的引號內名稱。 這個目標會定義 my_program 目標,您可以使用選取器 asan/my_program 將其套用為:

executable("my_program") { ... }

部分目標會使用 GN output_name 變數覆寫輸出名稱 (通常是為了提供全域不重複的二進位檔名稱,避免發生衝突)。在這種情況下,變體選取器會比對覆寫的輸出名稱,因此您仍可使用 asan/my_program 將 ASan 套用至該名稱:

executable("bin") {
  output_name = "my_program"
}

在某些情況下,範本可能會以不明顯的方式覆寫輸出名稱。如果發現變體不相符,簡單的做法是直接在建構目錄中尋找二進位檔,然後使用該名稱。

進階選取器

您也可以在花括號中提供 GN「範圍」,做為變數選取器,完全控管相符目標的建構方式。這些設定必須在「gn args」中設定,而不是在「fx set」指令列中設定。詳情請參閱 select_variant 建構引數說明文件。

如要查看可用變數清單,並進一步瞭解如何定義新變數,請參閱known_variants建構引數。

常見的變體名稱

  • debug:未經過最佳化的編譯。
  • release:最佳化編譯。
  • asan位址清除器,用於編譯時檢查記憶體誤用情形,例如釋放後使用和陣列存取超出範圍。
  • ubsan未定義行為清除器,用於在編譯時檢查未定義行為,例如整數溢位和指標對齊錯誤。
  • asan-ubsan:asan + ubsan 的組合。
  • lto:針對整個程式進行最佳化的連結時間最佳化
  • thinlto精簡連結時間最佳化是較輕量的全程式最佳化,可加快編譯速度。
  • coverage:用於產生 C++ 的程式碼涵蓋率資訊。
  • coverage-rust:將涵蓋範圍套用至 Rust。由於 Rust 和 C++ 編譯器之間的 LLVM 程式庫版本有偏差,因此無法與 coverage 同時使用。
  • kasan:僅適用於核心。
  • gcc:使用 GCC 而非 Clang 進行編譯。這項設定僅支援啟動設定,且只會影響特定目標 (包括核心)。

fuzzer 下使用清除器執行測試時,會用到 asan-fuzzer 等模糊測試器變體。這些變體不適合手動選取,請按照模糊測試指示設定建構作業。

此外,還有一些適用於主機二進位檔 (在 Linux 或 Mac 主機電腦上執行的工具) 的變體簡寫選取器: * host_asan * host_asan-ubsan * host_coverage * host_coverage-rust * host_profile

部分預建項目可能不適用於所有變體。如要瞭解 ffmpeg 的相關資訊,請參閱 //src/media/lib/ffmpeg/BUILD.gn

疑難排解注意事項

確認變體是否已套用至二進位檔

每個變數都有專屬的輸出目錄和工具鍊名稱,名稱為 <architecture>-<variant name>。這些二進位檔隨後會複製到根層級的建構目錄,做為建構程序的一部分。舉例來說,以 x64 裝置為目標的 asan-ubsan 變數會使用 //build/toolchain/fuchsia:x64-asan-ubsan 工具鍊編譯,並將二進位檔放在 out/default/x64-asan-ubsan 中 (將「default」替換為您的建構目錄)。

執行 GN 後 (通常是建構的第一步),會產生一個檔案 binaries.json,其中包含每個二進位檔的資訊。您可以根據 dist 檔案名稱和 label (工具鍊名稱位於括號內),判斷編譯二進位檔時使用的變體。如果二進位檔可能在目標和主機上編譯,請一併注意記錄中的 os 欄位。以下是使用「asan-ubsan」變體,為 x64 編譯的 Fuchsia 二進位檔範例:

  {
    "cpu": "x64",
    "debug": "x64-asan-ubsan/exe.unstripped/blobfs",
    "dist": "x64-asan-ubsan/blobfs",
    "elf_build_id": "x64-asan-ubsan/blobfs.build-id.stamp",
    "label": "//src/storage/blobfs/bin:blobfs(//build/toolchain/fuchsia:x64-asan-ubsan)",
    "os": "fuchsia",
    "type": "executable"
  },

複製 ASan 失敗

我們的基礎架構會在啟用 ASan 的設定中執行測試。如要複製啟用 ASan 的基礎架構建構作業,請使用 fx repro <build_id> 並執行發出的指令。

請注意,這會建構基礎架構執行的所有測試,並將其安裝在系統映像檔中。這可能不盡理想,原因有二:

  • 建構所有測試通常既緩慢又沒必要。開發人員可能會發現,將套件標籤限制在所需的測試中,效果會更好。
  • 如果預先在系統映像檔中安裝所有測試,軟體部署工作流程就不會執行。

從啟用 ASan 的二進位檔啟動可執行檔

如果您嘗試使用 ASan 變體,可能會遇到類似以下的錯誤:

launcher: error: Launch: elf_load: handle_interp failed
dlsvc: could not open 'asan/ld.so.1'

Fuchsia 的架構是以套件和元件為基礎。每個元件都包含執行所需的所有共用程式庫。這有助於 Fuchsia 避免其他作業系統常見的程式庫版本控管問題。這也表示,如要從元件內執行二進位檔,您必須為該二進位檔提供適當的共用程式庫載入器。

Fuchsia 安裝的 /boot/ 目錄中有一組指令列程式,這些程式並未包含在套件中,而是位於開機檔案系統。這些程式沒有自己的共用程式庫載入器,而是使用執行這些程式的元件所提供的共用程式庫。這通常可行,因為 shls 等程式的依附元件非常少,而且非常常見。不過,我們無法保證元件的套件會提供足夠或相容的共用程式庫,以滿足指令列程式的需求。啟用 ASan 的套件通常不含這些程式的正確啟動器,因此大多數啟用 ASan 的元件都無法從 /boot 執行可執行檔。如果啟用 ASan 的元件嘗試執行這項操作,就會收到上述錯誤訊息。

幸好,修正方式是聲明依附元件,這也是所有套件本來就應該執行的動作。如果套件依附於二進位檔,則應將其宣告為依附元件,然後使用該宣告的依附元件,而非 /boot 目錄中的依附元件。以我們的建構系統為例,//build/config/fuchsia/zircon_images.gni 中定義的 zircon_extras_manifest 規則可讓您依附於 /boot 目錄中的任何二進位檔。這些檔案會安裝在 /pkg/bin/ 中,您應從該處執行。