Last update: 2025-02-21
This page provides important Bazel-related guidelines for Fuchsia developers working in-tree (i.e. with a fuchsia.git checkout). As the Bazel migration is a moving target, this page will be updated frequently to reflect important changes.
Summary
As of Q1 2025, the following guidelines apply:
If you do not perform product assembly, and do not write driver packages, do not worry about or start writing Bazel files in the Fuchsia tree.
If you define new product boards or input bundles, do that with Bazel targets and dedicated Bazel SDK rules, as in this example.
If you write Bazel driver packages that are only used by Bazel-defined boards, then define them in Bazel only, using dedicated Bazel SDK rules, as in this other example.
All new board development should happen in Bazel. If your board happens to depend on an existing GN driver package, expose it to the Bazel graph using the bazel_driver_package() template (example here).
Bazel-based driver packages must only depend on platform libraries that are exposed through the
@fuchsia_sdk
and@internal_sdk
repositories.@fuchsia_sdk
contains a set of libraries, that are distributed OOT, but does include "unstable" platform libraries to be used by driver developers (look for the(unstable)
marker in lines of the previous link).For example
@fuchsia_sdk//pkg:driver_power_cpp
exposes the library from the GN//sdk/lib/driver/power/cpp
library definition.@internal_sdk
contains similar definitions, but only for SDK atoms that are only available within the in-tree Fuchsia build, and thus can be even more unstable. However its removal is planned, in favor of moving all unstable atoms to@fuchsia_sdk
instead, so no atoms should be added there.Do not write BUILD.bazel files for internal platform libraries.
For now, duplicate BUILD.gn / BUILD.bazel definitions for the same non SDK libraries should be avoided.
If your driver needs to use a platform-internal library that has not been exposed as an unstable IDK atom yet, contact fuchsia-build-discuss@google.com to present your use case.
Ideally, adding a new unstable IDK atom should be enough, but there may be exceptions, as described in the dedicated section below.
All Bazel targets must still be wrapped by a GN target to be visible to post-build clients.
In particular, one or more Bazel test packages must be wrapped by a GN
bazel_test_package_group()
target definition, to ensure thatfx test
andbotanist
(our infra CI test runner tool) can know about them, build them on demand, and execute them.Invoking Bazel from a GN/Ninja action is very slow: it takes several seconds even if Bazel decides to do nothing. And only one can be run at a time.
These actions are defined by GN templates such as
bazel_action
, or one of its wrappers, and their instances are controlled using the//build/bazel:bazel_action_allowlist
target.Templates such as
bazel_build_group()
orbazel_test_package_group()
are used to invoke Bazel only once to build several Bazel targets together. This allows for much better parallelism.Avoid non-terminal GN targets that depend on Bazel artifacts
Due to the high-cost of crossing the GN/Bazel boundary, dependency chains that look like
GN -> Bazel -> GN -> Bazel -> GN
result in significantly slower incremental builds, and must be avoided.See dedicated section below for details.
Dual BUILD.bazel
and BUILD.gn
definitions
It is inevitable that many of our targets will require dual definitions
in equivalent BUILD.gn
and BUILD.bazel
files during the rest of the
migration.
It is critical that such dual build files, if they exist, be kept in sync over time. It is also important to track which dual-defined targets exist in both graphs.
An initial and simple way to do that is to write them manually and use
matching LINT
If-This-Then-That blocks in both files to detect skew
during CL review.
A better way, is to use a tool such as the recently-introduced
bazel2gn
to automatically convert a BUILD.bazel
to
an equivalent BUILD.gn
.
For now, bazel2gn
is only a prototype, that only handles Go targets. It will
be improved over time to support more use cases, but it should not be used by
Fuchsia developers yet, its use being restricted to the Fuchsia Build Team.
In both cases, comment markers, and associated tooling, will be introduced to track which targets are dual-defined in both graphs.
Dependencies between the GN and Bazel graphs
Due to the high-cost of crossing the GN/Bazel boundary, dependency chains that
look like GN -> Bazel -> GN -> Bazel -> GN
result in significantly slower
incremental builds Developer experience is also frustrating due to lack of
clarity when looking at real dependencies, and build failures can become much
harder to understand and fix.
At the moment, the minimum chain looks like GN -> Bazel -> GN
because the
whole build is controlled by GN, and post-build clients only view GN-specific
target definitions, so any Bazel artifacts must be wrapped through GN-specific
targets.
The build team is working actively on making Bazel targets natively visible to
avoid that last Bazel -> GN
edge.
This requires modifying post-build tools and scripts (e.g. fx test
and many
others) to see Bazel outputs directly, and be able to rebuild them on demand
without invoking Ninja.
Exposing platform libraries as SDK atoms
For a target to be visible in @fuchsia_sdk
, the following must be true:
Their type must match one of our supported IDK atom schemas, which means:
- No Rust source libraries.
- No Go source libraries.
They must be defined in the GN graph (there is no support for defining SDK/IDK atoms in Bazel right now).
They cannot be
testonly = true
, due to restrictions at the GN / Bazel boundary.They cannot have conditional dependencies. Our IDK schema does not support them, and for good reasons.
Source libraries cannot depend on non-SDK libraries. All their transitive dependencies must be part of the SDK too.
They must be defined with an SDK-compatible GN template, e.g.:
sdk_source_set()
: for C++ source libraries.sdk_static_library()
: for prebuilt static C++ libraries.sdk_shared_library()
: for prebuilt shared C++ libraries.fidl()
withsdk_category
set: for FIDL definition files.zx_library()
withsdk_publishable = true
: for C++ source libraries that also need to be linked into the kernel, the bootloader(s) or theuserboot
program.sdk_fuchsia_package()
: for prebuilt Fuchsia packages.
If your platform library cannot follow these restrictions, contact the fuchsia-build-discuss@google.com mailing list to discuss alternatives. Alternatives may include dual-graph target definitions that need to be tracked for the rest of the migration.
Document History
2025-02-21: Initial version