<<../../_common/components/_declaring_intro.md>>
<<../../_common/components/_declaring_manifests.md>>
<<../../_common/components/_declaring_shards.md>>
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.
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.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() }}
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.
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.