在 Fuchsia 版本中建構變數

摘要

本文說明「建構變體」的實作方式。這是 Fuchsia 建構系統的功能,可建構主機和裝置二進位檔的檢測特別最佳化版本。

讀者必須熟悉 GN toolchain() 執行個體,並應已閱讀下列文件:

建構變化版本總覽

Fuchsia 建構作業定義了幾種建構變體,例如:

  • asanubsan 變體分別用於建構機器碼,並搭配 Clang 的 Address SanitizerUndefined Behaviour Sanitizer。甚至還有結合兩者的 asan-ubsan 變體。

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

  • profile 變體也用於建構插碼程式碼,但目的是支援設定檔引導最佳化。

  • thinltolto 變數用於建構二進位檔,並啟用連結時間最佳化。

  • gcc 變體用於使用 GCC 編譯器 (而非 Clang) 建構特定 Zircon 核心片段,有助於找出可能以非常重要的方式影響核心的細微機器碼產生問題。

  • 其他幾種變體則適用於特殊需求,這些變體全都在 //build/config/BUILDCONFIG.gn 檔案中定義,並使用本文件其餘部分所述的慣例。

一般來說,單一建構變化版本會模擬:

  • 一組額外設定,用於定義建構變體二進位檔及其依附元件時套用的編譯器、組譯器或連結器標記。

  • 一組要加入建構圖中最終變體二進位目標的選用隱含依附元件 (即執行檔、可載入模組,有時甚至是共用程式庫)。

舉例來說,假設「asan」建構變化版本用於啟用 Clang 的 Address Sanitizer 支援功能。在實務上,建構啟用 Address Sanitizer 的 Fuchsia 可執行程式時,至少需要:

  • 建構可執行檔及其所有依附元件時,將 -fsanitize=address 標記同時傳遞至 Clang 編譯器和連結器 (如果是 Fuchsia,則包括 C 程式庫)。

  • 執行階段可用的 Asan 執行階段 (libclang_rt.asan.so),以及其本身的依附元件 (即 libc++.solibc++abi.solibunwind.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_dirroot_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 時需要這些變數 (請參閱 //sdk/lib/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。如果省略 nameconfigs 不得為空白,且會用於衍生名稱 (方法是使用破折號加入名稱)。

  • tags:選用清單,內含描述變體屬性的任意形式字串 (請參閱工具鍊和變體標記)。

  • toolchain_args:選用範圍,其中定義的每個變數都會覆寫這個變體工具鍊環境中的建構引數。

  • host_onlytarget_only:選用範圍,可包含上述任何欄位。這些值分別只用於主機或目標 (即裝置) 工具鍊。這裡包含的任何欄位也不應位於外部範圍。

以下是一些例子:

含有單一設定的變數描述元範例

{
  configs = [ "//build/config/lto" ]
  tags = [ "lto" ]
}

上述範圍定義了名為 "lto" 的變體描述元 (由於範圍中沒有 name 鍵,因此名稱是從 configs 中的值推斷而來,而這裡只包含單一項目)。

套用這個變種版本會新增 //build/config/lto:lto 設定 (定義於 //build/config/lto/BUILD.gn 中),且該檔案也應包含 //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:建構變數描述元的名稱。在基本工具鍊的環境中,這是空字串;否則,這是用於建立目前 GN toolchain() 執行個體的變數描述元名稱。

    各種工具鍊情境的名稱範例:

    //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。

  • configsremove_common_configsremove_shared_configs:要 config() 項目清單,直接來自目前的GN 描述元 (如有),否則為空白清單。

  • 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() 範本建立,且因此未使用 GN 內建的 C/C++ 和 Rust 支援功能,則為 true。這個工具鍊只包含 copyaction 目標。

目標定義很少使用這個全域變數的內容,根據目前的工具鍊環境變更設定。這類情況大多發生在低階目標,例如 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-ubsanhost_coveragehost_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:binexecutable() 目標,會產生名為 my_program 的 Fuchsia 程式二進位檔。由於建構作業的運作方式,這會產生 ${root_build_dir}/exe.unstripped/my_program${root_build_dir}/my_program,以及一些次要檔案 (在此忽略)。

  • 名為 //src/my/program:verify_binaryaction() 目標用於剖析程式二進位檔,以檢查或擷取其中的資訊 (假設是驗證匯入符號參照)。這個目標需要依附於第一個目標,但也要找出二進位檔的輸出位置,如下所示:

    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_toolchainhost_out_dir 全域變數

TBW

zircon_toolchain 變數

TBW

variant() 範本

TBW