Build system

Fuchsia builds use Generate Ninja (GN), a meta-build system that generates build files consumed by Ninja, which executes the actual build. The build system provides the tools to configure the build for a specific product and templates to build code for Fuchsia targets.

Build targets

You define individual build targets for GN using BUILD.gn files located with your project source code. The Fuchsia build system provides templates as GN imports (.gni) for you to declare Fuchsia artifacts, such as:

  • fuchsia_component(): Defines an executable component, containing the manifest, program binary, and resources.
  • fuchsia_package(): Defines a package containing one or more components for distribution in a package repository.
  • fuchsia_test_package(): Defines a package containing test components.

Below is an example of a BUILD.gn file for a simple component package with tests:

import("//build/components.gni")

executable("bin") {
  sources = [ "main.cc" ]
}

fuchsia_component("hello-world-component") {
  deps = [ ":bin" ]
  manifest = "meta/hello-world.cml"
}

fuchsia_package("hello-world") {
  deps = [
    ":hello-world-component",
  ]
}

fuchsia_component("hello-world-test-component") {
  testonly = true
  deps = [ ":bin_test" ]
  manifest = "meta/hello-world-bin-test.cml"
}

fuchsia_test_package("hello-world-tests") {
  test_components = [ ":hello-world-test-component" ]
}

A unique label composed of the target's name and the path to its BUILD.gn file identifies everything that can participate in the build. In the above example, the hello-world target might have a label that looks like this: //src/examples/basic:hello-world.

Build configuration

The GN front-end configures the build according to the chosen Fuchsia product configuration, collecting all the necessary packages and components required by the build. These targets are defined in various BUILD.gn files throughout the source tree. The output of the GN step is an optimized set of instructions for Ninja in the build directory.

The build system invokes GN when you run the fx set command to configure the build.

fx set minimal.x64

You should run the GN configuration step anytime you want to adjust the product configuration or the packages available to the build. GN is also invoked automatically during a build anytime one of the BUILD.gn files in the current configuration is changed.

Boards and products

The Fuchsia build system defines the baseline configuration for a Fuchsia build as a combination of a product and board. Together, these elements form the build configuration you provide to fx set.

Boards define the architecture that the build targets, which may affect what drivers are included and influence device specific kernel parameters.

This codelab targets the x64 board, which supports the Fuchsia emulator (FEMU) running on x64 architecture.

A product defines the software configuration that a build produces. This configuration may include what services are available and the user-facing experience.

This codelab targets the minimal_eng product.

Build

Once the GN build configuration is complete, Ninja consumes the generated build files and runs the appropriate compile, link, and packaging commands to generate the Fuchsia image.

The build system invokes Ninja when you run the fx build command to execute the current build configuration.

fx build

Exercise: Build Minimal

In this exercise, you'll build the minimal_eng product configuration from source to run on the x64 emulator board.

Configure the build

Set up the build environment for the minimal product and x64 board:

fx set minimal.x64

This command runs GN on the set of targets defined in the product's build configuration to produce the build instructions. It does not actually perform the build, but instead defines the parameters of what is considered buildable.

Inspect the build configuration

Once the build is configured, use fx list-packages to print the set of packages the build is aware of:

fx list-packages

This is a useful tool to determine if a package you need was properly included in the build configuration.

Build Fuchsia Minimal

Build the Minimal target with fx build:

fx build

Restart the emulator

  1. Run the following command to close any emulator instances you currently have open:

    ffx emu stop --all
    
  2. Start a new emulator instance:

    ffx emu start --headless
    

    When startup is complete, the emulator prints the following message and returns:

    Logging to "$HOME/.local/share/Fuchsia/ffx/emu/instances/fuchsia-emulator/emulator.log"
    Waiting for Fuchsia to start (up to 60 seconds)........
    Emulator is ready.
    

Inspect the device

Open another terminal window and run the following command to print the details of your device target:

ffx target show

Look for the build configuration of the target output:

Version: "2000-01-01T12:00:00+00:00"
Product: "minimal_eng"
Board: "x64"
Commit: "2000-01-01T12:00:00+00:00"

Notice that the configuration points to the build you just completed on your machine.

You are now running your own build of Fuchsia!

Exercise: Run a repository server and serve packages

In this exercise, you'll run a repository server to serve the packages available in the universe set to your running Fuchsia target on the emulator.

To learn more about repository and the different package sets, refer to RFC-0212 Package Sets

For example, running ffx debug connect will fail because the target needs the a component that exposes the fuchsia.debugger.Launcher capability. This is available in the debug_agent package in the universe set of minimal.x64.

List the packages in the universe set

Run fx list-packages to list the packages in the universe set. For minimal.x64 there is only one package:

fx list-packages --universe

The output shows only debug_agent package. The debug_agent includes a component that provides the fuchsia.debugger.Launcher capability. We will exercise this capability by launching a debugger in the next steps.

Start a repository server and register it with the Fuchsia target

The fx serve command starts the repository server and registers it with the target.

$ fx serve

You will see the following output if the command is run successfully:

2024-05-20 12:51:03 [serve] Discovery...
2024-05-20 12:51:07 [serve] Device up
2024-05-20 12:51:07 [serve] Registering devhost as update source
Serving repository '/usr/local/google/home/amituttam/fuchsia/out/minimal.x64/amber-files' to target 'fuchsia-emulator' over address '[::]:8083'.

Leave this command running the foreground. To run in verbose mode pass the --verbose or -v flag to fx serve.

Exercise: Run the debugger and list the running processes

With the repository server running, and the Fuchsia target configured to resolve packages from that repository, we can run a command that resolves the package and runs the component within.

First, let's run logs so we can see what is happening:

ffx log --filter debug_agent

Run the above command in a separate terminal, the output will be empty. Leave the command running. Here, we are filtering on debug_agent as the system will need to resolve that package to run the debugger.

In the other terminal, connect the debugger to the running system:

ffx debug connect

The command should launch zxdb and place you in an interactive shell. If you switch back to the other terminal with the running ffx log, you will see output along the lines of:

[01949.544917][pkg-resolver] INFO: attempting to resolve fuchsia-pkg://fuchsia.com/debug_agent as fuchsia-pkg://devhost/debug_agent with TUF
[01949.624075][pkg-resolver] INFO: updated local TUF metadata for "fuchsia-pkg://devhost" to version RepoVersions { root: 9, timestamp: Some(1715399460), snapshot: Some(1715399460), targets: Some(1715399460) } while getting merkle for TargetPath("debug_agent/0")
[01949.835760][pkg-resolver] INFO: resolved fuchsia-pkg://fuchsia.com/debug_agent as fuchsia-pkg://devhost/debug_agent to 3f9783abed30d70b72d5f0730bd6e6033481073126aac0b74cbbf2d14909497e with TUF
[01949.882891][debugger] INFO: [main_launcher.cc(182)] Start listening on FIDL fuchsia::debugger::Launcher.

Here the system attempts to resolve the debug_agent package and is able to do so from the configured devhost repository. Once it resolves the package, the component is launched that listens for the debugger launcher protocol.

Back to zxdb, you can now run ps to see the list of running processes on the system.

[zxdb] ps
 j: 1033 root
   p: 1102 bin/component_manager
   j: 1649
     j: 1780 bootstrap/console fuchsia-boot:///console#meta/console.cm
       p: 1822 console.cm
     j: 1989 bootstrap/archivist fuchsia-boot:///archivist#meta/archivist.cm
       p: 2051 archivist.cm
     j: 2064 bootstrap/console-launcher fuchsia-boot:///console-launcher#meta/console-launcher.cm
...