在 Fuchsia 版本中建構變數

摘要

本文件說明「建構變數」的實作方式: Fuchsia 建構系統,可用於建構「檢測服務」或 針對主機和裝置二進位檔進行特別最佳化的版本。

讀取器必須熟悉 GN toolchain() 執行個體 ,且應閱讀下列文件:

建構變數總覽

Fuchsia 版本定義了數種建構變數類型,例如:

  • asanubsan 變化版本可用來建構具有下列功能的機器碼: Clang 的 Address Sanitizer 分別為未定義的行為 Sanitizer。 甚至有 asan-ubsan 變化版本同時結合了這兩種變數。

  • coverage 變數是用來使用 Clang 的機器碼建構機器碼 啟用檢測型剖析功能,支援程式碼涵蓋率 集合。

  • profile 變數也會用於建構檢測程式碼。 而是支援設定檔導向最佳化功能

  • thinltolto 變化版本可用來建構具有下列功能的二進位檔: 已啟用連結時間最佳化功能。

  • gcc 變數是用來建構 Zircon 的特定部分 採用 GCC 編譯器的核心,而不是 Clang (這非常實用) 歸納出巧妙的機器程式碼產生問題 以的重要方式顯示核心)。

  • releasedebug 變化版本,提供覆寫的變數 預設編譯模式,這個選項取決於 args.gn 中的 is_debug 建構設定變數。

  • 特殊需求的幾個其他變體,全都定義 遵循慣例,在 //build/config/BUILDCONFIG.gn 檔案中 詳見本文件其他部分

一般來說,單一建構變數模型:

  • 一組額外設定,可定義編譯器、組合器或連結器標記 。

  • 要新增至最終的一組選用隱含依附元件 建構圖的變體二進位檔目標 (例如可執行檔、可載入的) 甚至共用程式庫)

以「asan」為例建構變數,可用於 啟用 Clang 的 Address Sanitizer 支援功能。於 練習,使用 Address Sanitizer 建構 Fuchsia 執行程式 enabled 需要 (最低):

  • -fsanitize=address 標記同時傳遞至 Clang 編譯器和連接器 。 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_build_dir 相同。root_out_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 用來產生以 ELF 為基礎的共用程式庫的 shlib 工具鍊。

必須在建構作業中使用 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 全域變數。

  • 變化版本描述元名稱清單 呼叫 SDK 中的 enable_variants 引數 variant_toolchain_suite() 範本。通常用於強制啟用 很少變體。select_variant

    例如,用於建構 C 程式庫的工具鍊 ASan 和 UBSan 變化版本 一律會啟用,因為建構核心 Fuchsia IDK 時需要這些資訊 (請參閱 //zircon/system/ulib/c/BUILD.gn)。

  • 顯示在 exclude_variant_tags敬上 variant_toolchain_suite() 的引數。通常可用來排除 避免將變化版本套用至指定基礎工具鍊

    例如,系統啟動載入程式會排除含有 "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:選用範圍,每個變數都定義了 此範圍內會覆寫工具鍊結構定義中的建構引數 此變數的 ID 序列

  • 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 欄 隱含依附元件

使用時間:remove_common_config,因為//build/config:no_rtti 是許多基本工具鍊的預設設定之一,但 RTTI 必須先啟用 UBSan 檢測才能正常運作。

此外,使用的代碼清單也更加詳盡。請注意, "kernel-excluded" 標記,用於防止這個變化版本 以便套用至任何核心機器碼

包含 toolchain_args 的變化版本描述元範例

{
  name = "release"
  toolchain_args = {
    is_debug = false
  }
}

此變體描述元已明確命名,但沒有 新增任何設定或依附元件另一方面 全域建構設定變數 is_debug 將 設為 false,藉此變更 在對應的變化版本工具鍊結構定義中定義。

通用變化版本

建構系統中較不為人知的功能稱為「通用變化版本」。這些 是額外的變體描述元,可與其他已知子類結合 運作方式如下:

  • 如果在 args.gn 中設定 is_debug=false,表示所有二進位檔 建構時使用的是最大最佳化,之後則是 "debug" 變化版本描述元 是由建構定義而成這可讓您在偵錯模式下建立特定目標,前提是: 無從得知

  • 同樣地,如果 is_debug=true (預設值),則 "release" 變數 描述元是由建構定義這樣您就能使用 並視需要使用完整的最佳化功能

  • 此外,上述通用變體會與所有其他已知 自動建構變數描述元。例如:如果 is_debug=false, 建構也會建立 "asan-debug""ubsan-debug" "thinlto-debug" 等。如果 is_debug=true,則會定義 "asan-release""ubsan-release""thinlto-release" 等。

請注意,這些變化版本描述元是由建構定義「有條件」。 根據 is_debug 的值。例如:沒有 "release" 變數及其所屬變數 組合 (通常是 is_debug=false),且沒有 "debug" 變數及其所屬變數 is_debug=true

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 清單是布林值標記,會設為 true 包含 "instrumentation" 標記值,方便取代 一些複雜的測試指示,例如:

    if (toolchain_variant.tags + [ "instrumentation" ]
        - [ "instrumentation" ] != toolchain_variant.tags) {
      # toolchain is instrumented
      ...
    }
    

    使用:

    if (toolchain_variant.instrumented) {
      # toolchain is instrumented
      ...
    }
    
  • is_pic_default:在可建構的工具鍊中,為 true 的布林值 ELF 位置獨立程式碼 (PIC)。這意味著 (例如 //build/toolchain/fuchsia:x64-shared) 或 會直接產生這類程式碼 (例如 //zircon/kernel/lib/userabi/userboot:userboot_arm64)。

  • with_shared:如果目前工具鍊有 shlib,此佈林值為 true 用於建構 ELF 共用資料庫 (例如 //build/toolchain/fuchsia:x64) 的工具鍊 使用 or 時,請在這類工具鍊中 (例如 //build/toolchain/fuchsia:x64-shared)。

  • configsremove_common_configsremove_shared_configs:清單 直接擷取自目前值的 config() 個項目 變化版本描述元 (如果有的話),或空白清單。

  • deps:列出要新增為依附元件的目標 GN 標籤清單 任何可連結的目標,繼承自變化版本描述元本身 (如果有的話)。

  • libprefix:如果是檢測設備,此為安裝前置字串字串 共用程式庫,否則會是空字串。詳情請參閱 toolchain variant 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:是一個布林值,如果此工具鍊由true basic_toolchain() 範本,因此不使用任何內建範本 GN 中針對 C/C++ 和 Rust 提供支援。只有 copyaction 個目標。

這個全域變數的內容很少用於目標定義 根據目前的工具鍊內容來改變其設定。這個 尤其是在 C 程式庫、核心產物等 低階目標中 非預先建構的檢測執行階段支援。

Toolchain 變化版本 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 建構系統支援選取 以及個別目標或指定目標群組 或方法是在select_variant 建構設定檔 (args.gn)。請參考以下範例:

# From out/default/args.gn
...

select_variant = [
  {
    label = [ "//src/sys/component_manager:bin" ]
    variant = "release"
  },
  "host_asan",
  "thinlto/blobfs",
  "ubsan",
]

清單中的每個值都是一個運算式,稱為 變化版本選取器,可以是範圍或字串 用於設定建構作業將變化版本套用至不同目標組合的方式。

如果已定義 select_variant 而非空白清單,其值將會 用於判斷如何建立「可連結」目標,例如執行檔、 建構圖中顯示的可載入模組和共用程式庫 基本工具鍊及其所有依附元件的結構定義。

select_variant 中顯示的變化版本選取器會進行比較 並選取第一個符合目前目標的內容。 因此,上述範例意味著:

  • //src/sys/component/manager:bin 程式二進位檔及其依附元件 建構時應一律使用 release 變化版本 (注意:這個範例 這會在 gn gen 的時間為 is_debug=false 時發生錯誤 args.gn 檔案,因為 "release" 變數不存在 在此情況下,請參閱「通用變化版本」瞭解原因)。

  • 主機二進位檔應在 "asan" 變化版本中建構。 請注意,"host_asan" 並非變化版本描述元名稱,而是 變化版本快速鍵

  • blobfs 程式裝置二進位檔應一律為 透過 "thinlto" 變化版本建構,且會執行連結時間 以及最佳化調整

  • 所有其他裝置二進位檔都應使用 "ubsan" 變化版本建構。

變化版本選取器

變化版本選取器是可顯示在全域 select_variant 版本中的值 設定變數。供建構系統用來控制變化版本 在基本工具鍊環境中定義可連結的目標時選擇。

支援以下三種類型的值:

  • 用來為一組指定目標定義一組比對條件的範圍。 該範圍的格式如下:

    • variant:特定變化版本描述元的名稱 只有在目前目標與所有條件相符時,才會使用這個值 其他 Deployment 規格

    • 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:如果已定義,則為布林值。如果選取器比對 使用主機工具鍊如果為 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",
    ]
    
  • 同樣地,每個通用變數及其本身的 也會再次套用至裝置二進位檔。

    也就是說,假設 args.gn 中的 is_debug=true, 下列做法會強制在版本內建構所有裝置的二進位檔 模式,而主機端仍會以偵錯模式建構。

    is_debug = true
    select_variant = [ "release" ]
    

    等同於:

    is_debug = true
    select_variant = [
      {
        variant = "release"
        host = false
      }
    ]
    

    如要在發布模式中強制主機二進位檔編譯, 可以使用明確範圍值,因為 定義如下:

    is_debug = true
    select_variant = [
      {
        variant = "release"
        host = true
      }
    ]
    

變化版本目標重新導向

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,
      ]

使用此設定時,建構作業一律會成功,且動作指令一律會 正確的二進位檔

這些作業全都會在建構作業中自動完成。最終效果是 相依項目不用考慮其依附元件是否是以 YAML 格式建構 不一定,這些結果就會仰賴輸出位置 至少對未移除的二進位路徑來說。

ELF 共用程式庫的輸出位置

TBW

特殊的 novariant 描述元

TBW

特殊的全域變數

host_toolchainhost_out_dir 全域變數

TBW

zircon_toolchain 變數

TBW

variant() 範本

TBW