Fuchsia build 中的 build 变体

概要

本文档介绍了“build 变体”的实现,build 变体是 Android Studio 的一项功能, Fuchsia 构建系统允许构建插桩特别优化的主机和设备二进制文件版本。

读者必须熟悉 GN toolchain() 实例 并应已阅读以下文档:

build 变体概览

Fuchsia build 定义了几种类型的 build 变体,例如:

  • asanubsan 变体用于通过 Clang 的 Address Sanitizer 和 分别为未定义的行为排错程序。 甚至还有一个结合了这两者的 asan-ubsan 变体。

  • coverage 变体用于通过 Clang 的 启用了基于插桩的分析,以支持代码覆盖率 。

  • profile 变体也用于构建插桩代码, 而是支持配置文件引导的优化。

  • thinltolto 变体用于通过如下方式构建二进制文件: 关联时优化。

  • gcc 变体用于构建 Zircon 的某些部件 使用 GCC 编译器而不是 Clang 从而消除了 对内核进行重要调用)。

  • releasedebug 变体,用于替换 默认编译模式,这由 args.gn 中的 is_debug build 配置变量。

  • 可满足特定需求的一些其他变体,这些变体均已定义 放在 //build/config/BUILDCONFIG.gn 文件中,并使用惯例 具体说明。

一般来说,单个 build 变体模型如下:

  • 一组用于定义编译器、汇编程序或链接器标记的额外配置 在构建变体二进制文件及其依赖项时应用的政策。

  • 一组要添加到最终 build 图中的变体二进制目标(即可执行文件、可加载文件) 模块,有时甚至是共享库)。

例如,假设“asan”build 变体,用于 启用 Clang 的 Address Sanitizer 支持。在 使用 Address Sanitizer 构建 Fuchsia 可执行程序 需要(至少):

  • -fsanitize=address 标志同时传递到 Clang 编译器和链接器 在构建可执行文件及其所有依赖项(包括 C 库(如果是 Fuchsia)。

  • Asan 运行时 (libclang_rt.asan.so) 可在运行时使用, 以及自己的依赖项(即 libc++.solibc++abi.solibunwind.so 二进制文件)。

基础工具链和变体工具链

build 变体始终应用于特定的“基础”工具链 提供由变体本身增强的默认设置。 这将创建一个新的 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 变体应用于用于 build 主机和 Fuchsia 设备二进制文件。

后者还可以使用 //build/toolchain/fuchsia:x64-asan-shared,作为 shlib 工具链,用于生成基于 ELF 的共享库。

必须使用 clang_toolchain_suite() 在 build 中定义基础工具链 或 zircon_toolchain_suite()。两个模板最终都调用 variant_toolchain_suite() 它实现了在需要时自动创建变体工具链的神奇功能。

工具链和变体标记

Fuchsia build 中的每个基本工具链都可以具有多个标记, 是自由格式字符串,用于描述工具链的属性。例如: "kernel" 标记用于指示使用工具链构建内核 工件(这很重要,因为没有 C 库,也没有标准 C++ 对某些目标市场具有重要意义的其他限制条件 定义)。

下面列出了所有有效的工具链标记 //build/toolchain/toolchain_tags.gni

同样,每个变体定义都有若干标记,用于描述属性。 变体。例如,"instrumentation" 标记用于 表明该变体会创建机器代码, 插桩(例如,Sanitizer 或 Profiler)

如需查看所有有效的变体标记及其文档的列表,请访问 //build/toolchain/variant_tags.gni

创建变体工具链时,系统会将全局 toolchain_variant.tags 值设为 将包含从基本工具链继承的标记,以及从基础工具链继承的标记 。

工具链变体实例化

构建系统只在需要时创建变体工具链。 存在大量可能的“工具链+变体”组合, 并同时创建所有此类请求会大大降低 gn gen 的速度。

构建系统不会急于创建所有变体,而是决定哪些变体 根据以下条件创建的工具链变体:

  • 变体选择器列表显示在 select_variant 全局变量。

  • 变体描述符名称列表,显示为 的 enable_variants 参数, variant_toolchain_suite() 模板。很少用于强制启用 即使 select_variant 为空,也很少会发生变体。

    例如,用于构建 C 库的工具链的 ASan 和 UBSan 变体 始终处于启用状态,因为构建 Core Fuchsia IDK 时需要用到这些内容 (请参阅 //zircon/system/ulib/c/BUILD.gn)。

  • 出现在 exclude_variant_tags variant_toolchain_suite() 的参数。很少用于排除 变体会应用到给定的基本工具链。

    例如,引导加载程序会排除带有 "instrumented" 的变体 因为无法运行排错程序或性能分析运行时 (请参阅 `//

变体描述符

变体描述符是用于描述 向构建系统提供给定的 build 变体它们通过 //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_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
  }
}

此变体描述符会明确指定, 添加任何配置或依赖项另一方面 全局 build 配置变量 is_debug 将 设置为 false,这会更改默认配置的数量 在相应的变体工具链上下文中定义。

通用变体

构建系统中鲜为人知的功能称为“通用变体”。这些 是与其他已知变体组合的其他变体描述符, 其工作原理如下:

  • 如果在 args.gn 中设置了 is_debug=false,则意味着所有二进制文件都应 采用最大限度的优化进行构建,则 "debug" 变体描述符 由 build 定义如果存在以下情况,允许在调试模式下构建特定目标: 。

  • 同样,如果 is_debug=true(默认值),则 "release" 变体 描述符由 build 定义。这样,您就可以使用 必要时进行全面优化。

  • 此外,上述通用变体会与所有其他已知变体组合起来, 变体描述符。例如:如果为 is_debug=false, 那么构建还将创建 "asan-debug""ubsan-debug""thinlto-debug" 等。如果为 is_debug=true,则将定义 "asan-release""ubsan-release""thinlto-release" 等。

请注意,这些变体描述符由 build 有条件地定义, 基于 is_debug 的值。例如,没有 "release" 变体, is_debug=false,并且没有 "debug" 变体及其 is_debug=true

toolchain_variant 全局变量

BUILD.gn*.gni 文件中时,全局 toolchain_variant 变量 可用于检索 current_toolchain 的变体相关信息。 这是一个具有以下架构的范围:

  • name:build 变体描述符的名称。此字段是 基本工具链的上下文,或者是变体描述符的名称, 否则用于创建当前的 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: 当前状态。请注意,对于某个工具链变体的 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" 标记值,提供此值是为了方便您替换 类似于 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)。这意味着 shlib 工具链 (例如 //build/toolchain/fuchsia:x64-shared)或基础工具链, 直接生成此类代码(例如 //zircon/kernel/lib/userabi/userboot:userboot_arm64)。

  • with_shared:一个布尔值,如果当前工具链具有 shlib,则该布尔值为 true 用于构建 ELF 共享库的工具链(例如 //build/toolchain/fuchsia:x64或位于此类工具链中(例如 //build/toolchain/fuchsia:x64-shared)时。

  • configsremove_common_configsremove_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:一个布尔值,true basic_toolchain() 模板,因此不使用任何内置 。它只有 copyaction 目标。

此全局变量的内容很少用于目标定义 根据当前工具链上下文更改其配置。这个 多发生于低级目标,如 C 库、内核工件 或插桩运行时支持。

工具链变体 libprefix

为了能够在单个文件中混用插桩和非插桩二进制文件 Fuchsia 软件包中,构建系统必须执行特殊步骤:

  • 使用插桩变体工具链构建的共享库 必须安装到 "lib/<variant>/" 而不是默认的 "lib/" 位置。

  • 可执行二进制文件必须使用如下链接器参数进行编译: "-Wl,-dynamic-linker=<variant>/ld.so.1",用于替换默认值 ("ld.so.1",它在 Fuchsia Clang 预构建工具链二进制文件中进行了硬编码。)

  • 一种特殊情况是,模糊测试 build 变体会使用非模糊测试 build 变体 库子目录的名称

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 构建系统支持选择将哪些 build 变体 以及针对哪些具体目标或目标组, 。为此,您需要定义 select_variant 变量, build 配置文件 (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 build 中的值 配置变量。供构建系统用来控制变体 在基本工具链环境中定义可关联目标时选择此项。

支持以下三种值:

  • 为一组目标定义一组匹配条件的范围。 该范围的格式如下:

    • 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 列表中的选择器顺序很重要:第一个选择器 与当前目标匹配的结果胜出,并确定该目标的构建方式。

变体快捷键

除了变体描述符之外,build 还设置了许多“快捷方式”, 是一些硬编码变体选择器范围值的已命名别名。build 添加 几个硬编码变体,并根据已知变体列表创建其他变体:

  • "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 变体选择机制。

此模板不应直接从 BUILD.gn 文件中调用,而应 由 Fuchsia build 为 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 的局限性,这是必要的。

启用 build 变体后,二进制文件目标的实际输出位置 因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,
      ]

使用此设置时,构建始终会成功,并且操作命令始终有效 处理正确的二进制文件。

这一切都是在 build 中自动完成的。最终效果是 而无需关心其依赖项是否是使用 无论特定变体是否是特定变体,都可以依赖输出位置 稳定,至少对于未剥离的二进制文件路径而言是稳定的。

ELF 共享库的输出位置

TBW

特殊的 novariant 描述符

TBW

特殊全局变量

host_toolchainhost_out_dir 全局变量

TBW

zircon_toolchain 变量

TBW

variant() 模板

TBW