The Fuchsia build system aims at building both boot images and updatable packages for various devices. The Fuchsia build system uses GN, a meta-build system that generates build files consumed by Ninja, which executes the actual build.
Note: Zircon uses a different build system, but it also uses 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 following sections cover several concepts around Fuchsia's build system.
The contents of the generated Fuchsia images are controlled by a combination of a board and a product. Boards and products are build targets that define the packages and dependencies that are included in images. For more information on the structure and usage of these build configurations, see boards and products.
Build targets are defined in BUILD.gn
files that exist throughout the source tree. These files use a Python-like syntax to declare buildable objects. For example:
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 through the 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.
When building Fuchsia using fx set
, you can specify a build optimization flag to control the trade-off between compilation time, runtime performance, and debuggability. The build optimization flags are --debug
, --balanced
, and --release
.
Choosing the right flag can significantly impact your development workflow, build times, and the performance characteristics of the resulting image.
Note: For full details, see Full comparison of build optimization flags.
--debug | --balanced | --release | |
---|---|---|---|
Primary focus | Debug assertions, optimized for use with the debugger | Compile speed and good runtime performance. | Max runtime performance and smallest size |
Compile time | Faster (Incremental) | Medium (2-4x faster than release for some targets) | Slower |
Runtime performance | Slower | Good (acceptable for most development) | Faster |
Binary size | Larger | Much smaller than debug, and slightly larger than release | Smaller |
Optimizations | Minimal | Some | Full |
Debug experience | Full | Between debug and release (slightly less debuggability than debug) | Minimal |
Recommended for | Active coding and debugging | Daily development and faster iterations | Production, benchmarking, performance analysis, final validation |
Append the desired flag to your fx set
command:
fx set PRODUCT.BOARD [--debug | --balanced | --release]
For example:
fx set core.x64 --debug
fx set core.x64 --balanced
--balanced
?The --balanced
flag was introduced to address the significant compilation time overhead of --release
builds, especially for large Rust and C++ targets. By selectively enabling optimizations and using faster alternatives like ThinLTO (instead of Full LTO) for C++ and more codegen units (i.e. threads at compile time) for Rust, --balanced
offers a better developer experience for tasks requiring better-than-debug performance.
As Fuchsia evolves, --release
builds may incorporate even more aggressive (and potentially slower to compile) optimizations like Rust Full LTO, PGO and higher optimization levels for performance-critical binaries. On the other hand, if you use --balanced
this will allow you to do performance-aware development so that you can benefit from ongoing compile-time improvements while maintaining good runtime characteristics.
This section does a full comparison between the build optimization flags:
--debug
--release
and --balanced
for initial builds due to lack of optimization passes. Incremental builds are typically the fastest.--balanced
Note: This optimization flag is recommended default for faster iteration with good performance.
--release
.--debug
and --release
slightly more debuggability than release. Some optimizations might make precise debugging harder than --debug
.--release
build, but significantly faster than --debug
. Performance is generally acceptable for most development and testing scenarios.--release
. For large Rust targets, this can be 2-4x faster.netstack3
compiles 4x faster (70s vs 280s).component_manager
compiles 2.6x faster (70s vs 180s).--debug
but want to avoid the long compile times of --release
.--debug
is too slow at runtime.--release
-O3
).The simplest way to execute a build is through the fx
tool by using fx set
to configure a build and then fx build
as described in fx workflows.
Configure the primary build artifacts by choosing the board and product to build:
{fx set}
fx set core.x64
You can also set an optimization flag on this command. See Build optimization flags. For example:
fx set core.x64 --balanced
{fx gn gen}
fx gn gen $(fx get-build-dir) --args='import("//boards/x64.gni") import("//products/core.gni")'
For a list of all GN build arguments, run:
fx gn args $(fx get-build-dir) --list
This creates a build directory (usually out/default
) that contains Ninja and Bazel files.
Once you have configured the build artifacts with fx set
, you can then build Fuchsia:
{fx build}
fx build
This is what gets run under the hood by fx build
.
In order to rebuild the tree after modifying source code, you can just re-run fx build
. This also applies 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.
These tips and tricks only apply for using the fx gn
command.
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 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:
Note: This only works for targets in the default toolchain. 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 through fx serve
, users must build the updates
group.
{fx build}
fx build //foo/bar/blah:dash
{fx build --host}
fx build --host //foo/bar/blah:dash
When running a build, Ninja keeps logs that can be used to view the steps of the build process. To analyze the timing of a specific build iteration:
Run a build as you normally would do. This generates the .nina_log
file in your output directory.
Use the fx ninjatrace2json
tool to convert the Ninja log into a trace file. For example:
fx ninjatrace2json <your_output_directory>/.ninja_log > trace.json
Load the resulting trace.json
file in a compatible trace viewer. For example, in Chrome, navigate to chrome://tracing
and click “Load”.
Alternatively, you can use fx report-last-build
. This command gathers comprehensive build logs and timing information.