This codelab walks through the process of defining and building a new product bundle in Fuchsia using the Bazel build system. A product bundle is the distributable artifact that contains all the images and metadata needed to flash, update, or emulate a Fuchsia product.
As part of this process, you will also define a product configuration to specify the software features, settings, and packages that make up the product.
Prerequisites
- Familiarity with Fuchsia's software assembly concepts.
- Basic understanding of Bazel build rules.
What is a product configuration?
A product configuration in Fuchsia defines the user experience for a specific product. It is distinct from a board configuration, which specifies hardware-specific details. A product configuration typically includes:
- Platform settings: Settings for the underlying Fuchsia operating system (e.g., build type, enabled system features).
- Product settings: Settings specific to the product experience (e.g., session shell, specific packages).
Product configurations are defined using the fuchsia_product_configuration
rule in BUILD.bazel files.
Writing a product configuration
Let's explore how to define a product configuration and use it to build a system image.
Basic setup
A product configuration is primarily a JSON object (represented as a dictionary
in Starlark) passed to the fuchsia_product_configuration rule.
# //products/my_product/BUILD.bazel
load(
"@rules_fuchsia//fuchsia:assembly.bzl",
"fuchsia_product_configuration",
)
fuchsia_product_configuration(
name = "product_config",
product_config_json = {
"platform": {
"build_type": "eng",
"feature_set_level": "standard",
},
"product": {},
},
)
Platform settings
The platform key in the configuration dictionary controls various aspects of
the Fuchsia system. Common fields include:
build_type: Controls the security and optimization level.eng: Engineering build. This build is best for debugging as it has assertions enabled and optimizations disabled.userdebug: This build is optimized like theuserbuild, but with some debug features and tools enabled.user: Production build. This build is fully optimized and secure.
feature_set_level: Defines the baseline set of features included in the system.embeddable: Minimal subset of bootstrap. This is optimized for memory constrained environments and does not self-update.bootstrap: Bootable, serial-only. Only the/bootstraprealm. No netstack or storage drivers. Primarily used for board-level bringup.utility: Smallest configuration with the/corerealm. Best for utility-type systems like recovery.standard: A "full Fuchsia" configuration. Includes netstack and self-update capabilities. This is the default.
storage: Configures the filesystem (e.g., Fxfs) and storage layout.
For a full list of platform settings, see the PlatformSettings documentation.
For example, a Fuchsia product configuration with platform settings may look like the following:
fuchsia_product_configuration(
name = "product_config",
product_config_json = {
"platform": {
"build_type": "eng",
"feature_set_level": "standard",
"storage": {
"filesystems": {
"volume": "fxfs",
},
},
},
"product": {},
},
)
Product settings
The product key is used for higher-level product settings.
One of the most important settings is the session. A session is the top-level component that defines the product's user experience (e.g., the graphical shell or main application).
To use a session, you must specify its URL and ensure the package containing the component is included in the base packages.
Base packages are the set of packages that are included in the system image. They are available immediately at boot, are immutable (read-only), and are updated as part of the system OTA.
For example, a Fuchsia product configuration with product settings may look like the following:
Example:
fuchsia_product_configuration(
name = "product_config",
product_config_json = {
"platform": {
"build_type": "eng",
"feature_set_level": "standard",
},
"product": {
"session": {
"url": "fuchsia-pkg://fuchsia.com/my_session#meta/my_session.cm",
},
},
},
base_packages = [
"//src/my_session:my_session_package",
],
)
For a full list of product settings, see the ProductSettings documentation.
Assembling the product image
Once you have a fuchsia_product_configuration, you can use the
fuchsia_product rule to assemble the final system image. This rule combines
your product configuration with a specific board configuration.
load(
"@rules_fuchsia//fuchsia:assembly.bzl",
"fuchsia_product",
)
fuchsia_product(
name = "image.x64",
board_config = "//boards:x64",
platform_artifacts = "//build/bazel/assembly/assembly_input_bundles:platform_eng",
product_config = ":product_config",
)
board_config: Points to the board configuration target.platform_artifacts: Points to the bundle of platform artifacts (AIBs) to use.
Creating a product bundle
To run your product on a device or emulator, you need to package it into a
Product Bundle using the fuchsia_product_bundle rule.
load(
"@rules_fuchsia//fuchsia:assembly.bzl",
"fuchsia_product_bundle",
)
fuchsia_product_bundle(
name = "my_product.x64",
product_bundle_name = "my_product.x64",
main = ":image.x64",
)
This target produces the artifacts needed for ffx product-bundle commands.
For example:
Run in emulator:
ffx emu start my_product.x64Flash to device:
ffx target flash -b my_product.x64
Registering with the build system
To build your product bundle, it must be registered with the GN build system. This involves the following steps:
Bridging to GN
Fuchsia's build system uses GN, but your product bundle is defined in Bazel. You
need to use the bazel_product_bundle GN template to create a bridge.
Create a BUILD.gn file in your product directory (e.g.,
//products/my_product/BUILD.gn):
# //products/my_product/BUILD.gn
import("//build/bazel/assembly/bazel_product_bundle.gni")
bazel_product_bundle("my_product.x64") {
testonly = true
product_bundle_name = "my_product.x64"
bazel_product_bundle_target = ":my_product.x64"
bazel_product_image_target = ":image.x64"
bazel_inputs_from_gn = [
"//boards/x64:x64.bazel_input",
"//build/images/flash:esp.bazel_input",
]
allow_eng_platform_bundle_use = true
}
Adding to allowlists
You may need to add your new product to the bazel_action_allowlist in
//build/bazel/BUILD.gn to avoid visibility errors:
# //build/bazel/BUILD.gn
group("bazel_action_allowlist") {
visibility = [
# ...
"//products/my_product:*",
]
# ...
}
You may also need to add it to the non_hermetic_deps visibility list in //build/BUILD.gn:
# //build/BUILD.gn
group("non_hermetic_deps") {
visibility = [
# ...
"//products/my_product:*",
]
# ...
}
This GN target (:my_product.x64) now represents your Bazel product bundle
in the GN build graph.
Adding to available products
Finally, add this new GN target to the global list of product bundles in
//products/BUILD.gn to make it discoverable by fx:
# //products/BUILD.gn
group("product_bundles") {
testonly = true
deps = [
# ... other products
"//products/my_product:my_product.x64",
]
}
Building the product
Fuchsia supports multi-product builds, meaning you can have multiple products available in the same build directory.
Configuring the build
Configure your build environment using fx set. You should use a product
configuration that enables the Bazel build system, such as fuchsia.x64:
fx set fuchsia.x64Setting the main product
To work with your specific product, set it as the "main" product bundle. This
configures fx tools to target your product by default:
fx set-main-pb my_product.x64Building the product
To build your currently selected main product (and its dependencies):
fx buildIf you want to explicitly build a specific product bundle regardless of the main setting:
fx build my_product.x64Switching products
You can switch the active "main" product bundle at any time without re-running
fx set by running fx set-main-pb again:
fx set-main-pb minimal.x64GN Arguments vs Assembly
In a multi-product build environment, all products share the same GN arguments
(defined by fx set). Therefore, you cannot use fx set ... --args to
configure product-specific features. Instead, all product configuration must
be done via the fuchsia_product_configuration Bazel rule as demonstrated in
this codelab.
Next steps
This codelab covered the basics of defining and building a new product bundle.
To continue learning, you can:
- Explore existing product configurations in
//products. - Learn more about Board configurations.