GN 根目标

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

不过,此功能在解析 BUILD.gn 文件时会以令人意外的方式更改 GN 的默认行为。本文档将对此进行说明。

GN 默认行为

出于历史原因,当在默认工具链的上下文中评估 BUILD.gn 文件时,GN 会实例化该文件中定义的每个目标,即使实际上没有任何内容依赖于这些目标

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

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

当 GN 解析此 build 方案时,会发生以下情况:

  • 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.gn 表示图的根,那么最终的 build 图将包含比所需更多的目标。

GN root_patterns

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

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

例如,使用 gn gen --root-pattern=//:* 和相同的 build 方案会以如下方式更改 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 构建图的大小,同时缩短 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() 目标,其输出被其他目标用作隐式输入,但不能直接依赖于这些目标。

  • 一些硬编码的基础设施工具预期始终在树中构建的目标。

  • 某些构建器配置本应列出但未在 universe_package_labels 中列出的目标,只是由于同一 BUILD.gn 文件中定义了其他必需目标而假定这些目标存在。

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