摘要
本文說明「建構變數」的實作方式,這是 Fuchsia 建構系統的一項功能,可讓您建構主機和裝置二進位檔的檢測或特別最佳化版本。
讀者必須熟悉 GN toolchain() 例項,並應已閱讀下列文件:
建構變化版本總覽
Fuchsia 建構定義了多種建構變化版本,例如:
asan
和ubsan
變化版本分別用於使用 Clang 的 Address Sanitizer 和 Undefined Behaviour Sanitizer 建構機器碼。甚至還有結合兩者的asan-ubsan
變化版本。coverage
變化版本用於建構機器程式碼,並啟用 Clang 的檢測器式剖析功能,以便收集程式碼涵蓋率。profile
變體也用於建構檢測程式碼,但可支援設定檔引導最佳化。thinlto
和lto
變化版本用於建構啟用連結時間最佳化的二進位檔。gcc
變體用於使用 GCC 編譯器 (而非 Clang) 建構 Zircon 核心的特定部分 (這有助於找出可能以非常重要的方式影響核心的機器碼產生問題)。其他幾種變化版本則可滿足特殊需求,這些變化版本皆在
//build/config/BUILDCONFIG.gn
檔案中定義,並採用本文件其餘部分所述的慣例。
一般來說,單一建構變化版本會模擬以下項目:
一組額外設定,用於定義建構變化版本二進位檔及其依附元件時要套用的編譯器、組譯器或連結器標記。
一組選用的隱含依附元件,可新增至建構圖中最終變數二進位檔目標 (即可執行檔、可載入的模組,甚至有時是共用程式庫)。
舉例來說,我們來看看「asan」建構變數,這個變數用於啟用 Clang 的 Address Sanitizer 支援功能。實際上,要建構啟用位址清理工具的 Fuchsia 可執行程式,至少需要:
在建構可執行檔及其所有依附元件 (包括 Fuchsia 中的 C 程式庫) 時,將
-fsanitize=address
標記傳遞至 Clang 編譯器和連結器。在執行階段可用的 Asan 執行階段 (
libclang_rt.asan.so
),以及其專屬依附元件 (即libc++.so
、libc++abi.so
和libunwind.so
二進位檔的特殊預先建構版本)。
基本和變數工具鍊
建構變化版本一律會套用至特定的「基本」工具鍊,該工具鍊會提供預設設定,並由變化版本本身加以擴充。這會建立新的 GN toolchain() 例項,稱為「變化版本工具鍊」,並具有自己的 root_out_dir
。例如:
//build/toolchain:host_x64
是用於建構主機二進位檔的基本工具鍊,其root_out_dir
為${root_build_dir}/host_x64
。//build/toolchain:host_x64-ubsan
是套用ubsan
變化版本所建立的變化版本工具鍊,其root_out_dir
為${root_build_dir}/host_x64-ubsan
。//build/toolchain/fuchsia:x64
是預設工具鍊 (針對以 x64 為基礎的裝置),用於建構 Fuchsia 使用者層級的二進位檔。由於這是預設值,因此其root_out_dir
與root_build_dir
相同。//build/toolchain/fuchsia:x64-asan
是將asan
變化版本套用至預設工具鍊所建立的變化版本工具鍊。其root_out_dir
會是${root_build_dir}/x64-asan
。
一般來說,//${tc_dir}:${tc_name}-${variant}
會是變化版本工具鍊,是將 ${variant}
變化版本套用至名為 //${tc_dir}:${tc_name}
的基礎工具鍊而建立,其 root_out_dir
一律會是 ${root_build_dir}/${tc_name}-${variant}
。
如果基本工具鍊含有 shlib 工具鍊,則其任何變化工具鍊也會有一個。最後,單一變化版本可套用至多個基礎工具鍊。
舉例來說,//build/toolchain:host_x64-asan
和 //build/toolchain/fuchsia:x64-asan
是變化版本工具鍊,是將相同的 asan
變化版本套用至用於建構主機和 Fuchsia 裝置二進位檔的基本工具鍊而建立。
後者也會將 //build/toolchain/fuchsia:x64-asan-shared
設為 shlib 工具鍊,以產生以 ELF 為基礎的共用程式庫。
您必須使用 clang_toolchain_suite()
或 zircon_toolchain_suite()
在建構中定義基礎工具鍊。這兩個範本都會呼叫 variant_toolchain_suite()
,後者會實作魔法,在需要時自動建立變化版本工具鍊。
工具鍊和變化版本標記
Fuchsia 版本中的每個基本工具鍊都可以有許多標記,這些標記是描述工具鍊屬性的自由格式字串。舉例來說,"kernel"
標記可用於指出使用工具鍊建構核心構件 (這點很重要,因為沒有 C 程式庫、標準 C++ 程式庫和其他對特定目標定義很重要的限制)。
所有有效的工具鍊標記清單位於 //build/toolchain/toolchain_tags.gni
中。
同樣地,每個子類定義都包含多個標記,用於描述子類的屬性。舉例來說,"instrumentation"
標記可用來表示這個變化版本會建立機器碼,執行執行階段檢測作業 (例如檢查器或剖析器)
如要查看所有有效的變化版本標記及其說明文件,請前往 //build/toolchain/variant_tags.gni
。
建立變化版本工具鍊時,全域 toolchain_variant.tags
值會包含從基礎工具鍊繼承的標記,以及從變化版本繼承的標記。
工具鍊變化版本例項化
建構系統只會在需要時建立變化版本工具鍊。可用的工具鍊 + 變化版本組合數量非常龐大,如果一次建立所有組合,gn gen
的速度會變得相當緩慢。
建構系統不會立即建立所有變化版本,而是會根據下列條件決定要建立哪些工具鍊變化版本:
在
select_variant
全域變數中顯示的變數選取器清單。變化版本描述符名稱清單,會顯示為
variant_toolchain_suite()
範本的enable_variants
引數。即使select_variant
為空白,也幾乎不會用於強制啟用部分變數。舉例來說,用於建構 C 程式庫的工具鍊的 ASan 和 UBSan 變化版本一律會啟用,因為建構 Core Fuchsia IDK 時需要這些變化版本 (請參閱
//zircon/system/ulib/c/BUILD.gn
)。在
variant_toolchain_suite()
的exclude_variant_tags
引數中顯示的變化版本標記清單。這項功能很少用於排除特定變化版本,以免套用至特定基礎工具鍊。舉例來說,系統啟動載入程式會排除含有
"instrumented"
標記的變化版本,因為無法在裝置啟動時執行消毒程式或剖析執行階段 (請參閱「//
變化版本描述詞
變化版本描述項是 GN 範圍,可向建構系統說明特定建構變化版本的屬性。這些是透過 //build/config/BUILDCONFIG.gn
中的 known_variants
變數定義,且每個範圍都應遵循以下嚴格的結構定義:
configs
:選用的 GN 設定標籤清單,會自動新增至含有此變數的每個目標。請注意,這個清單中的每個設定
${label}
都必須有目標${label}_deps
,這個變化版本中建構的每個目標都會自動依附於該目標。在大多數情況下,這會是空白的group()
。remove_common_configs
:選用的 GN 設定標籤清單,如果有,則應從使用此變化版本建構的任何目標中移除。當建構系統為二進位檔設定的部分預設設定不應用於特定變化版本時,有時就需要這麼做。remove_shared_configs
:GN 設定標籤的選用清單,類似remove_common_configs
,但只會在建構shared_library()
目標及其依附元件時套用。deps
:選用的 GN 目標標籤清單,會新增為使用此變化版本建構的任何可連結目標的隱含依附元件。name
:這個字串會以唯一名稱命名變化版本描述項,通常用於select_variant
。如果省略name
,configs
必須非空白,並用於產生名稱 (透過連接名稱和破折號)。tags
:選用清單,其中包含描述變化版本屬性的自由格式字串 (請參閱「工具鍊和變化版本標記」)。toolchain_args
:選用的範圍,其中這個範圍中定義的每個變數會覆寫這個變化版本的工具鍊背景資訊中的建構引數。host_only
和target_only
:可包含上述任一欄位的選用範圍。這些值分別只用於主機或目標 (即裝置) 工具鍊。此處所包含的任何欄位都不應出現在外部範圍中。
以下是一些例子:
含有單一設定的變數描述項範例
{
configs = [ "//build/config/lto" ]
tags = [ "lto" ]
}
上述範圍定義了名為 "lto"
的變化版本描述項 (由於範圍中沒有 name
鍵,因此系統會從 configs
中的值推斷名稱,而 configs
在此處只包含單一項目)。
套用這個變化版本會新增 //build/config/lto/BUILD.gn
中定義的 //build/config/lto:lto
設定,如果該設定沒有隱含的依附元件,該檔案也應包含 //build/config/lto:lto_deps
空白群組。例如:
# //build/config/lto/BUILD.gn
config("lto") {
cflags = [ "-flto" ]
asmflags = cflags
ldflags = cflags
rustflags = [ "-Clto=fat" ]
}
group("lto_deps") {
# Implicit dependencies for "lto" config.
# This is an empty group since there are none.
}
這個描述元使用 "lto"
標記,表示這個變化版本執行了連結時間最佳化。這個標記也能由 "thinlto"
描述元使用,後者會使用不同的設定。
含有多個設定的變化版本描述符範例
{
configs = [
"//build/config/sanitizers:ubsan",
"//build/config/sanitizers:sancov",
]
remove_common_configs = [ "//build/config:no_rtti" ]
tags = [
"instrumented",
"instrumentation-runtime",
"kernel-excluded",
"sancov",
"ubsan",
]
}
這會定義名為 "ubsan-sancov"
的變化描述項 (名稱是透過連結設定名稱和破折號,從 configs
清單衍生而來),用於建構機器碼,以便在執行階段偵測未定義的行為,並同時收集程式碼涵蓋率資訊。
請注意,這也需要定義 //build/config/sanitizers:ubsan_deps
和 //build/config/sanitizers:sancov_deps
,才能列出這些設定的隱含依附元件。
由於 //build/config:no_rtti
是許多基礎工具鍊的預設設定,但必須啟用 RTTI,才能讓 UBSan 檢測功能正常運作,因此會使用 remove_common_config
。
使用的標記清單也更為廣泛。請注意 "kernel-excluded"
標記,這是用來防止此變化版本套用至任何核心機器碼。
含有 toolchain_args
的變化版本描述元範例
{
name = "fully_optimized"
toolchain_args = {
optimize = "speed"
}
}
這個變化描述項會明確命名,且不會新增任何設定或依附元件。另一方面,這可確保全域建構設定變數 optimize
會設為「speed」,進而變更在對應的變種版本工具鍊內容中定義的預設設定數量。
toolchain_variant
全域變數
在 BUILD.gn
或 *.gni
檔案中,全域 toolchain_variant
變數可用於擷取 current_toolchain
的變體相關資訊。這是具有下列結構定義的範圍:
name
:建構變數描述元的名稱。這是基本工具鍊的內容中的空字串,或用於建立目前 GNtoolchain()
例項的變數描述項名稱。各種工具鍊情境的名稱範例:
//build/toolchain/fuchsia:x64 "" //build/toolchain/fuchsia:x64-shared "" //build/toolchain/fuchsia:x64-asan "asan" //build/toolchain/fuchsia:x64-asan-shared "asan"
base
:這是目前基礎工具鍊的完整 GN 標籤。請注意,對於工具鍊變化版本的 shlib 工具鍊,此值會指向最終的基本工具鍊。例如://build/toolchain/fuchsia:x64 //build/toolchain/fuchsia:x64 //build/toolchain/fuchsia:x64-asan //build/toolchain/fuchsia:x64 //build/toolchain/fuchsia:x64-shared //build/toolchain/fuchsia:x64 //build/toolchain/fuchsia:x64-asan-shared //build/toolchain/fuchsia:x64
tags
:自由格式字串清單,每個字串都會描述目前工具鍊例項及其變化版本的屬性。這只是工具鍊和變化版本代碼的聯合。instrumented
:布林值標記,如果tags
清單包含"instrumentation"
標記值,就會設為 true,方便在 GN 中取代複雜的測試指令,例如:if (toolchain_variant.tags + [ "instrumentation" ] - [ "instrumentation" ] != toolchain_variant.tags) { # toolchain is instrumented ... }
使用:
if (toolchain_variant.instrumented) { # toolchain is instrumented ... }
is_pic_default
:在可建構 ELF 位置無關程式碼 (PIC) 的工具鍊中為 true 的布林值。這表示 shlib 工具鍊 (例如//build/toolchain/fuchsia:x64-shared
),或是直接產生這類程式碼 (例如//zircon/kernel/lib/userabi/userboot:userboot_arm64
) 的基本工具鍊。with_shared
:如果目前的工具鍊含有 shlib 工具鍊,用於建構 ELF 共用程式庫 (例如//build/toolchain/fuchsia:x64
),或是在這樣的工具鍊 (例如//build/toolchain/fuchsia:x64-shared
) 中,則為布林值 true。configs
、remove_common_configs
、remove_shared_configs
:列出 GN 標籤至config()
項目,直接來自目前的變化版本描述項 (如有),否則為空白清單。deps
:目標的 GN 標籤清單,這些標籤會新增為任何可連結目標的依附元件,並繼承自變數描述元本身 (如有)。libprefix
:對於檢測到的變化版本,這是共用程式庫的安裝前置字串,否則為空字串。如需完整詳細資料,請參閱「工具鍊變化版本 libprefix」一節。exclude_variant_tags
:變化版本選取邏輯會在內部使用。繼承自clang_toolchain_suite()
或zircon_toolchain_suite()
呼叫,或直接繼承自目標定義。這是一組標記,用於排除要套用至基礎工具鍊或目標的變化版本,因為有時需要這麼做。suffix
:此值為"-${toolchain_variant.name}"
,如果名稱為空白則為""
。在內部使用,用於簡化不設條件的展開作業。supports_cpp
:如果這個工具鍊支援 C/C++,則為true
的布林值。supports_rust
:如果這個工具鍊支援 Rust,則為true
的布林值。is_basic
:如果這個工具鍊是由basic_toolchain()
範本建立,則為true
的布林值,因此不會使用 GN 中任何針對 C/C++ 和 Rust 的內建支援。只包含copy
或action
目標。
這個全域變數的內容很少被目標定義使用,因為目標定義會根據目前工具鍊的情況變更設定。這類問題通常發生在低階目標上,例如 C 程式庫、核心構件或未預先建構的檢測工具執行階段支援。
工具鍊變化版本 libprefix
為了能夠在單一 Fuchsia 套件中混合經過檢測和未經檢測的二進位檔,建構系統必須執行特殊步驟:
使用檢測變化版本工具鍊建構的共用程式庫,必須安裝至
"lib/<variant>/"
,而非預設的"lib/"
位置。可執行的二進位檔必須使用
"-Wl,-dynamic-linker=<variant>/ld.so.1"
等連結器引數編譯,這會覆寫預設值 ("ld.so.1"
,這是在 Fuchsia clang 預先建構的工具鍊二進位檔中硬式編碼)。在特殊情況下,模糊測試的建構變數會使用程式庫子目錄的非模糊測試建構變數名稱。
toolchain_variant.libprefix
變數的定義如下,可輕鬆支援所有這些內容:
variant name libdir libprefix note
no variant ---> lib/ "" (default target toolchain)
thinlto ---> lib/ "" (uninstrumented)
asan-ubsan ---> lib/asan-ubsan/ "asan-ubsan/" (instrumented)
asan-fuzzer ---> lib/asan/ "asan/" (instrumented + fuzzing)
這可用來將安裝位置設為 "lib/${toolchain_variant.libprefix}"
,並將連結器標記設為 "-Wl,-dynamic-linker=${toolchain_variant.libprefix}ld.so.1"
。
變化版本選取
Fuchsia 建構系統支援選取要啟用的建構變化版本,以及這些變化版本適用於哪些個別目標或目標群組。方法是在建構設定檔 (args.gn
) 中定義 select_variant
變數。請參考以下範例:
# From out/default/args.gn
...
select_variant = [
{
label = [ "//src/sys/component_manager:bin" ]
variant = "lto"
},
"host_asan",
"thinlto/blobfs",
"ubsan",
]
清單中的每個值都是運算式,稱為變異基因選取器,可以是作用範圍或字串,用於設定建構作業如何將變異基因套用至不同目標組合。
當 select_variant
已定義且不是空白清單時,其值會用於決定如何建構可連結的目標,例如在基本工具鍊的背景下,在建構圖中顯示的可執行檔、可載入的模組和共用程式庫,以及所有相關的依附元件。
系統會依序比較 select_variant
中顯示的子類別選取器,並選取與目前目標相符的第一個子類別。因此,上述範例表示:
//src/sys/component/manager:bin
程式二進位檔及其依附元件一律應使用lto
變數進行建構。主機二進位檔應在
"asan"
變化版本中建構。請注意,"host_asan"
不是變化版本描述項名稱,而是變化版本捷徑。blobfs
程式裝置二進位檔應一律使用"thinlto"
變化版本進行建構,以便執行連結時間最佳化。所有其他裝置二進位檔都應使用
"ubsan"
變數建構。
變化版本選取器
變化版本選取器是全域 select_variant
建構設定變數中可顯示的值。在基本工具鍊的情況下,定義可連結的目標時,建構系統會使用這些屬性來控制變化版本選取。
支援三種類型的值:
定義一組目標的比對條件。該範圍的格式如下:
variant
:指定的變化描述項名稱,只有在目前目標符合範圍內其他部分定義的所有條件時才會使用。label
:如果已定義,則必須是合格的 GN 標籤清單 (包含:
,但不含工具鍊標籤,例如//src/sys/foo:foo
)。name
:如果已定義,則為 GN 標籤目標名稱清單 (例如//src/sys/foo:bar
目標的名稱為「bar」)。dir
:如果已定義,則為 GN 標籤目錄路徑清單 (例如//src/sys/foo:bar
目標的路徑為"//src/sys/foo"
)。output_name
:如果已定義,則為目標output_name
值清單 (預設為其target_name
)。target_type
:如果已定義,則為與目標類型相符的字串清單。有效值為"executable"
、"test"
、"loadable_module"
、"shared_library"
和其他幾個值。testonly
:如果已定義,則為布林值。如果為 true,選取器會將目標與testonly=true
配對。如果為 false,選取器會比對不含testonly=true
的目標。host
:如果已定義,則為布林值。如果為 true,則選取器會比對主機工具鍊中的目標。如果為 false,則選取器會在目標工具鍊中比對。
包含簡單名稱 (例如
"asan"
) 的字串,可指向變化版本快速鍵,這是先前選取器範圍值的別名。舉例來說,
"coverage"
值等同於下列範圍:{ variant = "coverage" host = false }
字串,其中包含以目錄路徑 (例如
"thintlo/blobfs"
) 分隔的變化捷徑名稱和輸出名稱。這是方便的格式,可避免寫入等效範圍,如下例所示:{ variant = "thinlto" host = false output_name = [ "blobfs" ] }
select_variant
清單中的選取器順序很重要:系統會選取與目前目標相符的第一個選取器,並決定該目標的建構方式。
變化版本捷徑
除了變化版本描述項外,建構作業也會設定多個「捷徑」,這些是幾個硬式編碼變化版本選取器範圍值的命名別名。這個版本會新增一些硬式編碼,並從已知變數清單建立其他變數:
"host_asan"
捷徑的定義是使用"asan"
變化描述符建構主機二進位檔,在技術上等同於下列選取器範圍值清單:# Definition for the `host_asan` variant shortcut [ { variant = "asan" host = true } ]
同樣地,也存在
host_asan-ubsan
、host_coverage
、host_profile
和其他幾個。每個變化版本描述元名稱都有對應的捷徑,可專門套用至裝置二進位檔。也就是說,
"ubsan"
快捷鍵等同於以下選取器範圍值清單:[ { variant = "ubsan" host = false } ]
因此,在
select_variant
中使用變化版本描述元名稱時,只會將其套用至裝置二進位檔,如下所示:# Applies the `ubsan` variant to device binaries, not host ones! select_variant = [ "ubsan", ]
變體目標重新導向
variant_target()
範本
//build/config/BUILDCONFIG.gn
中定義的 variant_target()
範本會實作核心建構變數選取機制。
請勿直接從 BUILD.gn
檔案呼叫此範本,而是由 Fuchsia 版本為 executable()
、loadable_module()
、shared_library()
和其他幾個與可連結的目標 (也就是使用靜態連結器建立的目標) 定義的包裝函式範本叫用。
這項作業會針對每個目標,在建構圖的每個工具鍊背景中,將 select_variant
的內容與目標的屬性 (即目標類型和一些額外引數) 進行比較,以便:
1) 為目標計算「建構工具鍊」,也就是用於建構實際二進位檔的 GN 工具鍊例項,以及其依附元件。
2) 如果目前的工具鍊是建構工具鍊,請照常建構目標。
3) 否則,請建立 group()
或 copy()
目標,以便將建構工具組中的目標重新導向 (即公開依附)。這是否為群組或副本,取決於 variant_target()
實作中完整記錄的微妙條件,但請參閱下列子節以瞭解部分說明。
如要保留部分可連結目標的輸出位置,就必須使用 copy()
目標,而 group()
則可用於不需要保留輸出位置的情況。
在大多數情況下,executable()
或 loadable_module()
目標都需要 copy()
,而 shared_library()
目標則需要 group()
。
可連結的變數二進位檔的輸出位置
GN 設定語言的重大設計限制是,除了少數例外狀況,指定的目標定義「不會知道任何關於其依附元件的資訊」,除了標籤以外。這會造成問題,因為在許多情況下,特定目標都需要知道其依附元件的輸出位置,或這些依附元件實際上是哪種類型的目標。
為了說明這項操作,請參考以下範例:
名為
//src/my/program:bin
的executable()
目標,會產生名為my_program
的 Fuchsia 程式二進位檔。由於建構作業的運作方式,這會產生${root_build_dir}/exe.unstripped/my_program
和${root_build_dir}/my_program
,以及一些次要檔案 (在此處忽略)。名為
//src/my/program:verify_binary
的action()
目標,用於剖析程式二進位檔,以便檢查或擷取其中的資訊 (假設它會驗證匯入符號參照)。這個目標必須依附於第一個目標,但也要找出二進位檔的輸出位置,例如:
action("//src/my/program:verify_imports")
script = "check-my-imports.py"
deps = [ "//src/my/program:bin" ]
inputs = [ get_label_info(deps[0], "root_out_dir") + "/my_program" ]
...
|
| deps
|
v
executable("//src/my/program:bin")
output_name = "my_program"
# outputs: [
${root_build_dir}/exe.unstripped/my_program,
${root_build_dir}/my_program,
]
在此情況下,action()
可以使用 get_label_info("<label>", "root_out_dir")
的資料夾,猜測程式二進位檔的位置,並在動作本身中硬式編碼 output_name
值。這會違反抽象層,但考量到 GN 的限制,這項做法是必要的。
啟用建構變化版本後,二進位目標的實際輸出位置會根據 select_variant
而變更。如果使用簡單的 group()
實作變化版本重新導向,圖表會變成:
action("//src/my/program:verify_imports")
script = "check-my-imports.py"
deps = [ "//src/my/program:bin" ]
inputs = [ get_label_info(deps[0], "root_out_dir") + "/my_program" ]
...
|
| deps
|
v
group("//src/my/program:bin")
|
| public_deps
|
v
executable("//src/my/program:bin(//build/toolchain/fuchsia:x64-asan")
output_name = "my_program"
# outputs: [
# ${root_build_dir}/x64-asan/exe.unstripped/my_program,
# ${root_build_dir}/x64-asan/my_program,
# ]
問題是頂層動作中的 inputs
值並未變更,因此其指令會嘗試在舊位置 (${root_build_dir}/my_program
) 中尋找程式二進位檔,而不是在新位置 (${root_build_dir}/x64-asan/my-program
) 中尋找。因此,建構作業會使用過時的構件,或是因檔案遺漏而失敗。
在動作中剖析 select_variant
的成本過高,因此為瞭解決這個問題,可執行和可載入的模組目標需要使用 copy()
目標,而非 group()
,以確保未經去除的二進位檔會複製至原始位置。圖表會變成:
action("//src/my/program:verify_imports")
script = "check-my-imports.py"
deps = [ "//src/my/program:bin" ]
inputs = [ get_label_info(deps[0], "root_out_dir") + "/my_program" ]
...
|
| deps
|
v
copy("//src/my/program:bin")
outputs = [ "${root_build_dir}/my_program" ]
sources = [ "${root_build_dir}/x64-asan/my_program" ]
|
| public_deps
|
v
executable("//src/my/program:bin(//build/toolchain/fuchsia:x64-asan")
output_name = "my_program"
# outputs: [
${root_build_dir}/x64-asan/exe.unstripped/my_program,
${root_build_dir}/x64-asan/my_program,
]
在這種設定下,建構作業一律會成功,而且動作指令一律會處理正確的二進位檔。
以上所有步驟都會在建構期間自動完成。最終結果是,依附元件不需要在意其依附元件是否使用特定變化版本建構,因為它們可以依賴輸出位置保持穩定,至少對於未經精簡的二進位路徑而言是如此。
ELF 共用程式庫的輸出位置
TBW
特殊 novariant
描述元
TBW
特殊全域變數
host_toolchain
和 host_out_dir
全域變數
TBW
zircon_toolchain
變數
TBW
variant()
範本
TBW