The Fuchsia build system aims at building both boot images and updatable packages for various devices. To do so, it uses GN, a meta-build system that generates build files consumed by Ninja, which executes the actual build.
Note that Zircon uses a different build system, though still using GN and Ninja.
If you are unfamiliar with Fuchsia's build system and GN, see Using GN build, which outlines the basic principles of the GN build system.
The contents of the generated image are controlled by a combination of a board and a product that are the minimal starting configuration of a Fuchsia build. Boards and products define dependency sets that define the packages that are included in images, updates, and package repositories. boards and products documents the structure and usage of these build configurations.
A bundle is a grouping of related packages within a part of the source tree,
such as all tools or all tests. An overview of bundles is provided in
bundles. A set of top-level bundles are defined in
//bundles
.
Build targets are defined in BUILD.gn
files scattered all over the source
tree. These files use a Python-like syntax to declare buildable objects:
import("//build/some/template.gni")
my_template("foo") {
name = "foo"
extra_options = "//my/foo/options"
deps = [
"//some/random/framework",
"//some/other/random/framework",
]
}
Available commands (invoked using gn cli tool) and constructs (built-in target
declaration types) are defined in the GN reference. There are
also a handful of custom templates in .gni
files in the
//build
project.
Fuchsia defines many custom templates to support defining and building Fuchsia specific artifacts.
The simplest way to this is through the fx
tool, as described in
fx workflows. Read on to see
what fx
does under the hood.
The rest of this document assumes that gn
and ninja
commands are
available in your PATH
. These commands can be found in
prebuilt/third_party/gn/<platform>
and
prebuilt/third_party/ninja/<platform>
respectively. Alternatively, if
you want to avoid modifying your PATH
, you can prefix all invocations
with fx
, i.e. fx gn
or fx ninja
.
First configure the primary build artifacts by choosing the board and product to build:
fx gn gen $(fx get-build-dir) --args='import("//boards/x64.gni") import("//products/core.gni")'
This will create a build directory (usually out/default
) containing Ninja
files.
The equivalent fx set
command is:
fx set core.x64
For a list of all GN build arguments, run:
fx gn args $(fx get-build-dir) --list
For documentation on the select_variant
argument, see Variants.
The next step is to run the actual build with Ninja:
fx ninja -C $(fx get-build-dir)
This is what gets run under the hood by fx build
.
In order to rebuild the tree after modifying some sources, just rerun
Build step. This holds true even if you modify BUILD.gn
files as GN adds
Ninja targets to update Ninja targets if build files are changed! The same
holds true for other files used to configure the build. Any change of source
that requires a manual re-invocation of the Gen step is a build bug and
should be reported.
fx gn desc $(fx get-build-dir) //path/to/my:target
fx gn refs $(fx get-build-dir) //path/to/my:target
Various host tools (some used in the build itself) need to be built along with the final image.
To reference a build target for the host toolchain from a module file:
//path/to/target(//build/toolchain:host_x64)
To reference a build target for the host toolchain from within a BUILD.gn
file:
//path/to/target($host_toolchain)
If a target is defined in a GN build file as //foo/bar/blah:dash
, that target
(and its dependencies) can be built with:
fx ninja -C $(fx get-build-dir) -j64 foo/bar/blah:dash
Note that this only works for targets in the default toolchain.
Note: Building package targets does not result in an updated package
repository, because the package repository is updated by the updates
group
target. In order for updated package changes to be made available via fx serve
, users must build the updates
group.
GN extensively documents which Ninja targets it generates. The documentation is accessible with:
fx gn help ninja_rules
You can also browse the set of Ninja targets currently defined in your output directory with:
fx ninja -C $(fx get-build-dir) -t browse
Note that the presence of a Ninja target does not mean it will be built - for that it needs to depend on the “default” target.
Add -d explain
to your Ninja command to have it explain every step of its
execution.
When running a build, Ninja keeps logs that can be used to generate visualizations of the build process:
- Delete your output directory - this is to ensure the logs represent only the build iteration you’re about to run;
- Run a build as you would normally do;
- Get https://github.com/nico/ninjatracing;
- Run
ninjatracing <output directory>/.ninja_log > trace.json
; - Load the resulting json file in Chrome in
about:tracing
.
Make sure it rolls up to a label defined in a module file, otherwise the build system will ignore it.
You likely forgot to run both commands of Build step.
TODO(pylaligand): command showing path to default target
TODO(pylaligand): .gn, default target, GN labels insertion