GN 根目标

Fuchsia build 使用 GN 的新 root_patterns 功能,以大幅缩减 GN 和 Ninja build 图的大小。这样可以显著缩短 gn gen 时间,并缩短 Ninja 启动时间。

不过,在以可能出乎意料的方式解析 BUILD.gn 文件时,此功能改变了 GN 的默认行为。本文档介绍了操作方法。

GN 默认行为

由于历史原因,当在默认工具链的上下文中对 BUILD.gn 文件中定义的每个目标进行求值时,GN 都会实例化 BUILD.gn 文件中定义的每个目标,即使实际上没有任何目标依赖于这些目标也是如此。

例如,请考虑以下三个 BUILD.gn 文件,它们各自定义了两个目标,并且它们之间存在一些依赖关系:

 _//BUILD.gn____    _//foo/BUILD.gn__    _//bar/BUILD.gn_
|               |  |                 |  |                |
|   A           |  |         D -------------> E          |
|               |  |                 |  |                |
|      B --------------> C           |  |         F      |
|_______________|  |_________________|  |________________|

当 GN 解析此构建计划时,会发生以下情况:

  • GN 首先加载 //BUILD.gn 并对其进行评估。由于它使用默认工具链,因此它会为该文件中的所有条目(即 //:A//:B)创建目标。

  • GN 会遵循刚刚创建的目标的依赖项,因为 //:B 依赖于 //foo:C,因此它会首先加载 //foo/BUILD.gn 并对其进行评估。

  • 由于它仍在默认工具链中,因此也会实例化该文件中的所有目标,从而创建 //foo:C//foo:D,即使后者不是 //:A//:B 的依赖项也是如此

  • 它再次遵循依赖项,并将加载 //bar/BUILD.gn、评估它并创建此处定义的所有目标,因此也就是 //bar:E//bar:F

如果一个 build 图假定 //BUILD.gn 表示该图的根,那么这会生成包含比所需数量远多的目标的最终 build 图。

GN root_patterns

您可以通过在 .gn 文件中设置 root_patterns 或使用 --root-pattern=<pattern> 命令行选项(一次或多次)来更改此默认行为。

这些标签定义了目标标签模式的列表,用于过滤要创建在默认工具链评估的 BUILD.gn 文件中的哪些非依赖项目标。

例如,使用具有相同构建方案的 gn gen --root-pattern=//:* 会在以下方面改变 GN 的行为:

  • GN 首先加载 //BUILD.gn 并对其进行评估。由于它在默认工具链中,因此创建的文件中的任何目标,因为它们与模式匹配(//:* 实际上表示“//BUILD.gn 中的任何目标”)。因此,它像之前一样创建 //:A//:B

  • GN 会遵循依赖项,然后加载 //foo/BUILD.gn 并对其进行评估。它会创建 //foo:C,因为它是其先前创建的某个目标的直接依赖项。但是,它不会创建 //foo:D,因为其标签与 //:* 模式不匹配。

  • GN 就会停止运行,因为它没有创建 //foo:D,也没有理由加载 //bar:BUILD.gn

因此,GN 创建了 3 个目标,而不是最终 build 图中的 6 个。

实际结果

在实践中,使用此功能可以显著减小 GN build 图的大小,从而缩短 gn gen 时间。例如,使用 fx set minimal.x64 配置:

                        Default     --root-pattern=//:*    Reduction

Target count             183761              48375          -73%
Ninja files size (MiB)    571.7              180.2          -68%
`fx set` peak RAM (GiB)    5.02               2.89          -42%
`gn gen` time (s)          14.9               6.15          -58%
`fx set` time (s)          16.0               6.77          -57%

//:root_targets 目标。

//BUILD.gn 文件现在定义了一个名为 root_targets 的顶级目标,该目标可用于向绝对必须在 build 图中的目标添加依赖项,即使没有其他目标依赖于它们也是如此。

这在少数情况下至关重要:

  • 某些特殊的 generated_file() 目标,其输出会被其他目标用作隐式输入,但无法直接依赖于此类目标,例如 //build/bazel:legacy_ninja_build_outputs

  • 硬编码的基础架构工具应始终在树中构建一些目标。

  • 某些构建器配置需要的一些目标错误地未在其 universe_package_labels 中列出,只是由于同一 BUILD.gn 文件中定义的其他必需目标而假定存在它们。

尽量不要向此名单添加内容。如果您确实需要始终在最终 Ninja build 清单中定义某些内容,最好从任何其他顶级 //BUILD.gn 目标中查找真正的传递依赖项。