Declaring components

<<../../_common/components/_declaring_intro.md>>

<<../../_common/components/_declaring_manifests.md>>

<<../../_common/components/_declaring_shards.md>>

Building components

The Fuchsia build system provides templates as GN imports in //build/components.gni to build and package software into Fuchsia components. Below is an example of a BUILD.gn file for a simple C++ component:

{% verbatim %}
import("//build/components.gni")

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

resource("my_file") {
  sources = [ "my_file.txt" ]
  outputs = [ "data/{{source_file_part}}" ]
}

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

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

This file contains the following main elements:

  • executable(): Compiles the source code into a binary. This target varies depending on the programming language. For example, an executable target can be used for C++, rustc_binary for Rust, go_binary for Golang.
  • resource(): Optional named collection of data files to copy as resources into another GN target. These files are accessible to the binary inside the component's namespace.
  • fuchsia_component(): Collects the binary, component manifest, and additional resources together into a single target. This target compiles the manifest source into a component declaration using cmc.
  • fuchsia_package(): Unit of distribution for components. Allows one or more components to be hosted in a package repository and included in the target device's package sets. This target generates the package metadata and builds the Fuchsia Archive (.far) file.

Packages can contain multiple components, listed as deps in the fuchsia_package() template. You can simplify the build file for packages containing only one component using the fuchsia_package_with_single_component() template.

The following simplified BUILD.gn example is equivalent to to the previous example:

{% verbatim %}
import("//build/components.gni")

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

resource("my_file") {
  sources = [ "my_file.txt" ]
  outputs = [ "data/{{source_file_part}}" ]
}

fuchsia_package_with_single_component("hello-world") {
  manifest = "meta/hello-world.cml"
  deps = [
    ":bin",
    ":my_file",
  ]
}
{% endverbatim %}

Note: For more details on the GN syntax of the component build rules, see the components build reference.

Exercise: Create a new component

In this exercise, you'll build and run a basic component that reads the program arguments and echoes a greeting out the system log.

To begin, Create a project scaffold for a new component called echo-args in the //vendor/fuchsia-codelab directory:

mkdir -p vendor/fuchsia-codelab/echo-args

Create the following file and directory structure in the new project directory:

  • {Rust}

    //vendor/fuchsia-codelab/echo-args
                            |- BUILD.gn
                            |- meta
                            |   |- echo.cml
                            |
                            |- src
                                |- main.rs
    
    • BUILD.gn: GN build targets for the executable binaries, component, and package.
    • meta/echo.cml: Manifest declaring the component's executable and required capabilities.
    • src/main.rs: Source code for the Rust executable binary and unit tests.
  • {C++}

    //vendor/fuchsia-codelab/echo-args
                            |- BUILD.gn
                            |- meta
                            |   |- echo.cml
                            |
                            |- echo_component.cc
                            |- echo_component.h
                            |- main.cc
    
    • BUILD.gn: GN build targets for the executable binaries, component, and package.
    • meta/echo.cml: Manifest declaring the component's executable and required capabilities.
    • echo_component.cc: Source code for the C++ component functionality.
    • main.cc: Source code for the C++ executable binary main entry point.

Add program arguments

The component manifest file defines the attributes of the component‘s executable, including program arguments, and the component’s capabilities. Add the following contents to meta/echo.cml:

{% set cml_rust %} {% includecode gerrit_repo=“fuchsia/fuchsia” gerrit_path=“examples/components/echo/rust/meta/echo.cml” region_tag=“manifest” adjust_indentation=“auto” %} {% endset %}

{% set cml_cpp %} {% includecode gerrit_repo=“fuchsia/fuchsia” gerrit_path=“examples/components/echo/cpp/meta/echo.cml” region_tag=“manifest” adjust_indentation=“auto” %} {% endset %}

  • {Rust}

    echo-args/meta/echo.cml:

    {{ cml_rust|replace("echo_example_rust","echo-args")|trim() }}
    
  • {C++}

    echo-args/meta/echo.cml:

    {{ cml_cpp|replace("echo_example_cpp","echo-args")|trim() }}
    

Log the arguments

Open the source file for the main executable and add the following import statements:

  • {Rust}

    echo-args/src/main.rs:

    {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/echo/rust/src/main.rs" region_tag="imports" adjust_indentation="auto" %}
    
  • {C++}

    echo-args/main.cc:

    {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/echo/cpp/main.cc" region_tag="imports" adjust_indentation="auto" %}
    
    #include "vendor/fuchsia-codelab/echo-args/echo_component.h"
    

Add the following code to implement the main() function:

  • {Rust}

    echo-args/src/main.rs:

    {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/echo/rust/src/main.rs" region_tag="main" adjust_indentation="auto" %}
    
  • {C++}

    echo-args/main.cc:

    {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/echo/cpp/main.cc" region_tag="main" adjust_indentation="auto" %}
    

This code reads the program arguments and passes them to a function called greeting() to generate a response for the syslog entry.

Add the following code to implement the greeting() function:

  • {Rust}

    echo-args/src/main.rs:

    {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/echo/rust/src/main.rs" region_tag="greeting" adjust_indentation="auto" %}
    
  • {C++}

    echo-args/echo_component.h:

    {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/echo/cpp/echo_component.h" region_tag="greeting" adjust_indentation="auto" %}
    

    echo-args/echo_component.cc:

    #include "vendor/fuchsia-codelab/echo-args/echo_component.h"
    
    {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/echo/cpp/echo_component.cc" region_tag="greeting" adjust_indentation="auto" %}
    

This function creates a simple string from the list of provided arguments based on the length of the list.

Add to the build configuration

Update the program's dependencies in your BUILD.gn file:

{% set gn_rust_binary %} {% includecode gerrit_repo=“fuchsia/fuchsia” gerrit_path=“examples/components/echo/rust/BUILD.gn” region_tag=“executable” adjust_indentation=“auto” %} {% endset %}

{% set gn_rust_component %} {% includecode gerrit_repo=“fuchsia/fuchsia” gerrit_path=“examples/components/echo/rust/BUILD.gn” region_tag=“component” adjust_indentation=“auto” %} {% endset %}

{% set gn_cpp_binary %} {% includecode gerrit_repo=“fuchsia/fuchsia” gerrit_path=“examples/components/echo/cpp/BUILD.gn” region_tag=“executable” adjust_indentation=“auto” %} {% endset %}

{% set gn_cpp_component %} {% includecode gerrit_repo=“fuchsia/fuchsia” gerrit_path=“examples/components/echo/cpp/BUILD.gn” region_tag=“component” adjust_indentation=“auto” %} {% endset %}

  • {Rust}

    echo-args/BUILD.gn:

    {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/echo/rust/BUILD.gn" region_tag="imports" adjust_indentation="auto" %}
    
    group("echo-args") {
      testonly = true
      deps = [
        ":package",
      ]
    }
    
    {{ gn_rust_binary|replace("echo_example_rust","echo-args")|trim() }}
    
    {{ gn_rust_component|replace("echo_rust","echo-args")|trim() }}
    
    fuchsia_package("package") {
      package_name = "echo-args"
      deps = [ ":component" ]
    }
    
  • {C++}

    echo-args/BUILD.gn:

    {% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/echo/cpp/BUILD.gn" region_tag="imports" adjust_indentation="auto" %}
    
    group("echo-args") {
      testonly = true
      deps = [
        ":package",
      ]
    }
    
    {{ gn_cpp_binary|replace("echo_example_cpp","echo-args")|trim() }}
    
    {{ gn_cpp_component|replace("echo_cpp","echo-args")|trim() }}
    
    fuchsia_package("package") {
      package_name = "echo-args"
      deps = [ ":component" ]
    }
    

Add your new component to the build configuration:

fx set workstation_eng.x64 --with //vendor/fuchsia-codelab/echo-args

Run fx build and verify that the build completes successfully:

fx build

In the next section, you'll integrate this component into the build and test the output in the system log.