Fuchsia 构建系统使用的清单文件格式

Fuchsia build 系统使用多个“清单”文件来指明如何将文件安装到容器中,例如将其复制到 Fuchsia 软件包归档或启动文件系统映像中。

本页介绍了这些文件格式,它们在 build 中使用,但不应在 build 之外公开。

请注意,用于生成和处理这些文件的脚本和 .gni 文件位于 Fuchsia 源代码树中的 //build/dist/ 下。

FINI (Fuchsia INI) 清单文件格式

FINI 清单格式由构建期间调用的多个工具使用:用于生成 Fuchsia 软件包归档的 ffx package build 命令或用于生成 ZBI 映像的 zbi 工具。

语法非常简单:每行文本都类似于 <destination>=<source>,其中 <destination> 是相对于最终容器顶部的目标文件路径,<source> 是相对于当前目录(在大多数情况下为 build 目录)的源内容文件路径。

请注意,目标路径不得以目录分隔符开头,并且 FINI 文件不支持 Windows INI 文件格式的注释、部分和其他功能

例如:

bin/foo=foo
lib/ld.so.1=user.libc_x64/libc.so
meta/foo.cm=obj/src/foo/cml/foo_component/foo.cm
meta/package=gen/src/foo/foo_meta_package.txt

分发清单文件格式

这是一个 JSON 文件,必须包含一个列表,其中每个项都是一个 JSON 对象,作为单个“distribution”(分发)条目,用于说明如何将一个源文件安装到容器中,以及为生成该源文件的目标提供 GN 标签。此处使用的架构如下:

  • source:源路径字符串(必需)。

  • destination:目标路径字符串(必需)。

  • label:指向生成源文件的目标的 GN 标签。仅用于调试(可选)。

示例:

  {
    "destination": "bin/foo",
    "source": "x64-asan/foo",
    "label": "//some/dir:foo"
  }

虽然在概念上与 FINI 清单类似,但分发清单提供的信息(GN 标签)稍多一些,这在出现问题时非常有助于调试。它们还会被另一组工具使用。

部分分发清单文件格式

FINI分发清单是通过处理名为“部分分发清单”的中间文件生成的。

部分清单由 GN 元数据收集针对同一依赖项树中的目标生成。它是一个 JSON 文件,其中包含对象“条目”列表。

有几种类型的条目用于描述 build 和安装要求的各个方面。它们都会合并到 FINI 或分发清单中。

//build/dist/distribution_manifest.py 中的 Python 模块包含用于处理这些文件的函数。

常规条目

这些条目与分发清单所用的架构相匹配。它们对应于要安装到给定目标路径的简单源文件。

  • source:源路径字符串(必需)。

  • destination:目标路径字符串(必需)。

  • label:指向生成源文件的目标的 GN 标签。仅用于调试(可选)。

  • elf_runtime_dir:仅适用于 ELF 可执行文件和可加载模块,是一个可选的目标目录路径,用于指定此二进制文件的 ELF 依赖项在运行时应位于何处。默认值为“lib”

当用于生成分发清单时,除非满足以下条件之一,否则系统会按原样将这些文件复制到输出文件中,而不使用 elf_runtime_dir 键:

  • 与其他常规条目具有相同的来源(如需了解详情,请参阅本部分),在这种情况下,系统只会保留其中一个条目。

  • 其源路径被重命名的条目使用(见下文)。

示例:

  {
    "destination": "bin/foo",
    "source": "x64-asan/foo",
    "label": "//some/dir:foo",
    "elf_runtime_dir": "lib/asan"
  },

复制条目。

这些条目用于表示 build 将特定文件复制到了新的输出位置。系统稍后会使用这些信息来正确处理已重命名的条目(见下文),否则会忽略这些信息。其架构如下:

  • copy_from:相对于 build 目录的源路径字符串(必需)。

  • copy_to:相对于 build 目录的目标路径字符串(必需)。

  • label:指向生成此条目的目标的 GN 标签(可选)。

例如,以下条目用于表示使用 ${BUILD_DIR}/x64-asan/foo 中的“asan”build 变体构建的“foo”可执行二进制文件也复制到了 ${BUILD_DIR}/foo

示例:

  {
    "copy_from": "x64-asan/foo",
    "copy_to": "foo"
    "label": "//some/dir:foo"
  }

请参阅下一部分,其中介绍了复制条目和重命名条目如何互动,并提供了实际示例。

重命名的条目

这些条目用于指明应将给定常规条目安装在备用目标位置。对于某些程序(例如 busybox),这非常有用,因为它们的行为会因用于启动它们的程序名称而异。renamed_binary() GN 模板依赖于它们。其架构为:

  • destination:目标路径字符串(必需)。

  • renamed_source:与另一个常规条目匹配的源路径(必需)。

  • label:指向生成此条目的目标的 GB 标签(可选)。

  • keep_original:一个布尔标志,设置为 true 表示应仍将原始重命名的二进制文件安装在容器中(可选)。

请注意,重命名条目只能指向常规条目的 source 路径,或指向副本条目的 copy_to 路径。使用未知路径或另一个重命名条目的目标路径会导致构建错误。

您可以多次重命名相同的条目。如果需要以不同的名称多次安装同一原始二进制文件,这会非常有用。

以下示例将 busybox 二进制文件作为 bin/cpbin/catbin/ls 安装在同一容器中。不过请注意,bin/busybox 不会安装到容器中。

  {
    "destination": "bin/busybox",
    "source": "busybox",
    "label": "//third_party/busybox:busybox"
  },
  {
    "destination": "bin/cp",
    "renamed_from": "busybox"
  },
  {
    "destination": "bin/cat",
    "renamed_from": "busybox"
  },
  {
    "destination": "bin/ls",
    "renamed_from": "busybox"
  }

如果任何重命名条目将 keep_original 标志设为 true,系统不会将原始条目从清单中移除,而是会保留原始二进制文件,如下所示:

  {
    "destination": "bin/busybox",
    "source": "busybox",
    "label": "//third_party/busybox:busybox"
  },
  {
    "destination": "bin/cp",
    "renamed_from": "busybox",
    "keep_original": true
  }

这将确保 bin/busyboxbin/cp 都安装到容器中。

文件条目

这些条目用于包含其他分发清单文件,这些文件可以由其他目标生成。其架构如下:

  • file:指向另一个分发清单文件的文件路径字符串(必需)。

  • label:默认的 GN 标签,如果包含的文件中的所有条目没有自己的 label 值,则会应用此标签(可选)。

分发文件包含项可以是递归的。

示例:

  {
    "file": "path/to/other.dist_manifest",
    "label": "//some/dir:label"
  }

清单文件中存在重复条目

根据 Fuchsia 构建的运作方式,清单文件(任何格式)可以提供多个使用同一 <destination> 路径的条目。然而,只要源路径或其内容相同,这种做法也有效;在这种情况下,系统会直接忽略重复项。

如果多个条目具有相同的目标路径,但源路径和内容不同,处理脚本会将其视为构建错误。

复制条目与重命名条目之间的互动

为了阐明复制条目和重命名条目的交互方式,请参考下面这个给定 renamed_binary() 目标的示例,该目标用于重命名 foo 二进制文件的安装位置。如果未选择任何 build 变体,相应的 build 清单将包含两个条目,如下所示:

  {
    "destination": "bin/foo",
    "source": "foo",
    "label": "//src:foo",
  },
  {
    "destination": "bin/foo_renamed",
    "renamed_from": "foo",
  },

第一个常规条目表明 ${BUILD_DIR}/foo 由默认工具链中的 //src:foo 目标构建,应安装到容器内的 bin/foo

第二个复制条目表明,以 ${BUILD_DIR}/foo 构建的二进制文件实际上应安装到 bin/foo_renamed,而不是其默认位置(即 bin/foo)。

从逻辑上讲,这相当于单个条目:

  {
    "destination": "bin/foo_renamed",
    "source": "foo",
    "label": "//src/foo",
  },

即第一个条目,其中仅更改了目标路径。

不过,启用使用 asan 变体构建相同内容时,清单内容将与之前略有不同:

  {
    "destination": "bin/foo",
    "source": "x64-asan/foo",
    "label": "//src:foo(//build/toolchain:x64-asan)",
  },
  {
    "copy_from": "x64-asan/foo",
    "copy_to": "foo",
  },
  {
    "destination": "bin/foo_renamed",
    "renamed_from": "foo",
  },

现在,第一个条目表明 ${BUILD_DIR}/x64-asan/foo 由 asan 工具链 (//build/toolchain:x64-asan) 中的 //src:foo 目标构建,并且仍默认安装到 bin/foo

第二个条目表明 ${BUILD_DIR}/foo${BUILD_DIR}/x64-asan/foo 的实际副本,因为我们的构建系统就是这样做的。

第三个条目与之前相同,因为 renamed_binary() 目标不了解构建 ${BUILD_DIR}/foo 时使用了哪个工具链或变体。

这在逻辑上等同于一个条目,如下所示:

  {
    "destination": "bin/foo_renamed",
    "source": "x64-shared/foo",
    "label": "//src/foo(//build/toolchain:x64-asan)",
  },

只有在启用 build 变体的情况下,系统才会使用副本条目,它们会将重命名的条目与特定于变体的常规条目相关联。所有这些信息分散的原因在于,每个条目都是通过 build 图中的不同目标生成的,并且在 GN 生成传递期间无法将所有内容关联起来。