blob: f79129a4850cf3bd575ecbcf200e0d2846e8db56 [file] [log] [blame] [view] [edit]
# Declaring components
<<../../../_common/components/_declaring_intro.md>>
<<../../../_common/components/_declaring_manifests.md>>
<<../../../_common/components/_declaring_shards.md>>
## Building components
The Fuchsia SDK system provides Bazel rules to build and package software
into Fuchsia components. The
[Fuchsia SDK environment](/docs/get-started/sdk/index.md#clone-the-sdk-samples-repository)
makes these rules available within a
[Bazel workspace](https://bazel.build/concepts/build-ref#workspace){:.external}
directory.
Within the Bazel workspace, you declare Fuchsia packages and components as
[Bazel targets](https://bazel.build/concepts/build-ref#targets){:.external} within
a [Bazel package](https://bazel.build/concepts/build-ref#packages){:.external},
described by a `BUILD.bazel` file.
Below is an example of a `BUILD.bazel` file for a simple C++ component:
```bazel
# Build rules provided by the Fuchsia SDK
load(
"fuchsia_cc_binary",
"fuchsia_component",
"fuchsia_component_manifest",
"fuchsia_package",
)
fuchsia_cc_binary(
name = "hello_world",
srcs = [
"hello_world.cc",
],
)
fuchsia_component_manifest(
name = "manifest",
src = "meta/hello_world.cml",
)
fuchsia_component(
name = "component",
manifest = ":manifest",
deps = [":hello_world"],
)
fuchsia_package(
name = "pkg",
package_name = "hello_world",
visibility = ["//visibility:public"],
deps = [
":component",
],
)
```
This file contains the following main elements:
* `fuchsia_cc_binary()`: Compiles the C++ source code into a binary, including
any necessary library dependencies.
* `fuchsia_component_manifest()`: Compiles the component manifest source file
(`.cml`) into a binary component declaration using `cmc`.
* `fuchsia_component()`: Collects the binary, component manifest, and additional
resources together into a single target.
* `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.
## 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 new project directory in your Bazel workspace for a new
component called `echo`:
```posix-terminal
mkdir -p fuchsia-codelab/echo
```
After you complete this section, the project should have the following directory
structure:
```none {:.devsite-disable-click-to-copy}
//fuchsia-codelab/echo
|- BUILD.bazel
|- meta
| |- echo.cml
|
|- echo_component.cc
|- echo_component.h
|- main.cc
```
* `BUILD.bazel`: Bazel 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.
Create `echo/meta/echo.cml` and add the following contents:
`echo/meta/echo.cml`:
```json5
{% includecode gerrit_repo="fuchsia/sdk-samples/getting-started" gerrit_path="src/echo/meta/echo.cml" region_tag="manifest" adjust_indentation="auto" %}
```
### Log the arguments
Create the `echo/main.cc` source file for the main executable and add the
following import statements:
`echo/main.cc`:
```cpp
{% includecode gerrit_repo="fuchsia/sdk-samples/getting-started" gerrit_path="src/echo/main.cc" region_tag="imports" adjust_indentation="auto" %}
#include "echo_component.h"
```
Add the following code for the the `main()` function:
`echo/main.cc`:
```cpp
{% includecode gerrit_repo="fuchsia/sdk-samples/getting-started" gerrit_path="src/echo/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.
Create `echo/echo_component.h` and `echo/echo_component.cc`, including the
following code to implement the `greeting()` function:
`echo/echo_component.h`:
```cpp
{% includecode gerrit_repo="fuchsia/sdk-samples/getting-started" gerrit_path="src/echo/echo_component.h" region_tag="greeting" adjust_indentation="auto" %}
```
`echo/echo_component.cc`:
```cpp
#include "echo_component.h"
{% includecode gerrit_repo="fuchsia/sdk-samples/getting-started" gerrit_path="src/echo/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.
<aside class="key-point">
<b>Logging and standard streams</b>
<p>Fuchsia has two main logging buffers; the system log (<code>syslog</code>)
and kernel's debug log (<code>klog</code>). By default, components do not have
stream handles for stdout and stderr available to record log messages from your
code. Instead, you must use one of Fuchsia's logging libraries or redirect these
streams to a Fuchsia log buffer.</p>
<p>For more details on logging from your code, see
<a href="/docs/development/diagnostics/logs/recording.md">Recording Logs</a>.</p>
</aside>
### Add to the build configuration
Create the `echo/BUILD.bazel` file and add the following build rules to include
the new component in the build configuration:
`echo/BUILD.bazel`:
```bazel
{% includecode gerrit_repo="fuchsia/sdk-samples/getting-started" gerrit_path="src/echo/BUILD.bazel" region_tag="imports" adjust_indentation="auto" exclude_regexp="fuchsia_cc_test|fuchsia_test_package|if_fuchsia" %}
{% includecode gerrit_repo="fuchsia/sdk-samples/getting-started" gerrit_path="src/echo/BUILD.bazel" region_tag="echo" adjust_indentation="auto" %}
```
Run `bazel build` and verify that the build completes successfully:
```posix-terminal
bazel build --config=fuchsia_x64 //fuchsia-codelab/echo:pkg \
--publish_to=$HOME/.package_repos/sdk-samples
```
In the next section, you'll integrate this component into the build and test the
output in the system log.