The Fuchsia build system aims at building both boot images and installable 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. Using GN build is a good intro to GN.
Note that Zircon uses an entirely different build system based on GNU Make. The rest of the build relies on Zircon being built ahead of time.
The contents of the generated image are controlled by a set of top level products. Products define sets of packages that are included in boot and system update images, preinstalled in paver images, and installable using the update system. products documents the structure and usage of fields in product definitions.
The contents of products are packages, which may aggregate or reference other packages and GN labels that are to be built. See packages for more information.
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.
These custom templates mostly define custom target declaration types, such as the [package declaration type][packages-source].
TODO(pylaligand): list available templates
The simplest way to this is through the fx
tool, as described in
Getting Started. Read on to see
what fx
does under the hood.
The first step is to build Zircon which uses its own build system:
$ scripts/build-zircon.sh
This is what gets run under the hood by fx build-zircon
, which is run by fx full-build
.
For a list of all options, run build-zircon.sh -h
. See Zircon's
Getting started and
Makefile options for details.
Then configure the content of the generated image by choosing the top level product to build:
# --products and --packages can be omitted to use the defaults, which are
# $layer/products/default.gni and empty, respectively.
$ buildtools/gn gen out/x64 --args='import("//garnet/products/product_name.gni") fuchsia_packages=["garnet/packages/my_stuff"]'
This will create an out/x64
directory containing Ninja files.
The equivalent fx set command is:
$ scripts/fx set x64 --products garnet/products/base.gni --packages garnet/packages/my_stuff
For a list of all GN build arguments, run buildtools/gn args out/x64 --list
.
For documentation on the select_variant
argument, see Variants.
The final step is to run the actual build with Ninja:
$ buildtools/ninja -C out/<arch> -j 64
This is what gets run under the hood by fx build
.
In order to rebuild the tree after modifying some sources, just rerun step
C. 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 package files used to configure the build.
You will want to rerun A and C.
You’ll most likely need to run A once if anything in the Zircon tree was changed. After that, run C again.
$ build/gn/preprocess_products.py --products '["garnet/products/default"]'
$ scripts/visualize_module_tree.py > tree.dot
$ dot -Tpng tree.dot -o tree.png
$ buildtools/gn desc out/x64 //path/to/my:target
$ buildtools/gn refs out/x64 //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:
$ buildtools/ninja -C out/x64 -j64 foo/bar/blah:dash
Note that this only works for targets in the default toolchain.
GN extensively documents which Ninja targets it generates. The documentation is accessible with:
$ buildtools/gn help ninja_rules
You can also browse the set of Ninja targets currently defined in your output directory with:
$ buildtools/ninja -C out/x64 -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 A before running B.
TODO(pylaligand): command showing path to default target
TODO(pylaligand): .gn, default target, mkbootfs, GN labels insertion