Codelab: Defining a new product configuration

This codelab walks through the process of defining a new product configuration in Fuchsia using the Bazel build system. Product configurations are used to specify the software features, settings, and packages that make up a Fuchsia product, independent of the hardware it runs on.

Prerequisites

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 the user build, 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 /bootstrap realm. No netstack or storage drivers. Primarily used for board-level bringup.
    • utility: Smallest configuration with the /core realm. 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 = "product_bundle.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.x64
    
  • Flash to device:

    ffx target flash -b my_product.x64
    

Next steps

This codelab covered the basics of defining a new product configuration.

To continue learning, you can: