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" ]
選取器語法
通常你會使用一組字串做為變體選取器。每個定義都會指定變體名稱,並視需要指定適用對象。系統會依您指定的順序測試選取器,並套用第一個相符的選取器。
如要全域套用具名變體,請單獨使用變體名稱,例如
asan或host_ubsan。這些全域選取器應列在最後。使用
variant_name/target_output_name形式 (例如asan-ubsan/ledger或host_asan/zxdb_tests),將具名變體套用至特定目標。這些項目應列在全域選取器之前,以覆寫較一般的規則。
變體會與二進位檔 (例如 executable、loadable_module、test 或 fuchsia_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/ 目錄中有一組指令列程式,這些程式並未包含在套件中,而是位於開機檔案系統。這些程式沒有自己的共用程式庫載入器,而是使用執行這些程式的元件所提供的共用程式庫。這通常可行,因為 sh 和 ls 等程式的依附元件非常少,而且非常常見。不過,我們無法保證元件的套件會提供足夠或相容的共用程式庫,以滿足指令列程式的需求。啟用 ASan 的套件通常不含這些程式的正確啟動器,因此大多數啟用 ASan 的元件都無法從 /boot 執行可執行檔。如果啟用 ASan 的元件嘗試執行這項操作,就會收到上述錯誤訊息。
幸好,修正方式是聲明依附元件,這也是所有套件本來就應該執行的動作。如果套件依附於二進位檔,則應將其宣告為依附元件,然後使用該宣告的依附元件,而非 /boot 目錄中的依附元件。以我們的建構系統為例,//build/config/fuchsia/zircon_images.gni 中定義的 zircon_extras_manifest 規則可讓您依附於 /boot 目錄中的任何二進位檔。這些檔案會安裝在 /pkg/bin/ 中,您應從該處執行。