Bazel migration guidelines

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 that fx test and botanist (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() or bazel_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.:

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