The Fuchsia build uses GN's new root_patterns
feature to considerably
reduce the size of the GN and Ninja build graphs. This results in significantly
faster gn gen
time, and Ninja startup time.
However, this feature changes GN's default behavior when parsing BUILD.gn
files
in ways that can be surprising. This document explains how.
GN default behavior
For historical reasons, GN will instantiate every target defined in a BUILD.gn
file
when the latter is evaluated in the context of the default toolchain, even if nothing
really depends on them.
As an example, consider the following three BUILD.gn
files that each define two targets,
with a few dependencies between them:
_//BUILD.gn____ _//foo/BUILD.gn__ _//bar/BUILD.gn_
| | | | | |
| A | | D -------------> E |
| | | | | |
| B --------------> C | | F |
|_______________| |_________________| |________________|
When GN parses this build plan the following happens:
GN starts by loading
//BUILD.gn
, and evaluating it. Because it uses the default toolchain, it creates targets for all entries in that file, i.e.//:A
and//:B
.GN follows dependencies of the targets it just created, since
//:B
depends on//foo:C
, it first loads//foo/BUILD.gn
and evaluates it.Because it is still in the default toolchain, it instantiates all targets in that file too, and thus creates
//foo:C
and//foo:D
, even though the latter is not a dependency of//:A
or//:B
It follows dependencies again, and will load
//bar/BUILD.gn
, evaluate it, and create all targets defined here, hence//bar:E
and//bar:F
This leads to the final build graph containing many more targets than
needed, if one assumes that //BUILD.gn
represents the root of the
graph.
GN root_patterns
It is possible to change this default behavior by setting
root_patterns
in the .gn
file,
or using the --root-pattern=<pattern>
command-line option (once or
more).
These define a list of target label patterns, used to filter which
of the non-dependency targets, present in BUILD.gn
files evaluated
in the default toolchain, to create.
For example, using gn gen --root-pattern=//:*
with the same build
plan will change GN's behavior in the following way:
GN starts by loading
//BUILD.gn
and evaluates it. Because it is in the default toolchain, any target in the file that is created, because they match the pattern (//:*
really means "any target in//BUILD.gn
"). It thus creates//:A
and//:B
as before.GN follows dependencies, then loads
//foo/BUILD.gn
and evaluates it. It creates//foo:C
because this is a direct dependency of one of the previous targets it created. However, it does not create//foo:D
, as its label does not match the pattern//:*
.GN stops here, since it didn't create
//foo:D
, it has not reason to load//bar:BUILD.gn
Thus GN creates 3 targets, instead of 6 in the final build graph.
Practical results
In practice, using this feature reduces the size of our GN build
graph considerably, speeding up the gn gen
time as well. For
example, using an fx set minimal.x64
configuration:
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%
The //:root_targets
target.
The //BUILD.gn
file now defines a top-level target named root_targets
that can be used to add dependencies to targets that absolutely must
be in the build graph even though nothing else depends on them.
This is critical for a few cases:
Some special
generated_file()
targets whose output is used as an implicit input by other targets, but which cannot be depended on directly.A few targets that hard-coded infra tools expect to always be built in the tree.
Some targets that are expected by some builder configurations that incorrectly didn't list them in their
universe_package_labels
, and just assumed their existence due to other required targets defined in the sameBUILD.gn
file.
Adding to this list should be minimized. It is always better to find
a real transitive dependency from any of the other top-level
//BUILD.gn
targets if you really need something to always be
defined in the final Ninja build manifest.