blob: db56374080984b020a80a18d087e504844d66c93 [file] [log] [blame] [view]
{% set v1_banner %}
<aside class="caution">
<b>Caution:</b> Caution: This format is used with
<a href="/docs/concepts/components/v1/README.md">legacy components</a>.
If you are still using legacy components, consider
<a href="/docs/contribute/open_projects/components/migration.md">migrating</a>
to the modern component framework.
</aside>
{% endset %}
# Build components
This document demonstrates how to build and test a component, highlighting best
practices for defining packages, components, and their tests.
## Concepts {#concepts}
You should understand the following concepts before building a component:
**[Packages][glossary.package]** are the unit of software distribution on
Fuchsia. Packages are a collection of files with associated paths that are
relative to the base of the package. For instance, a package might contain an
ELF binary under the path `bin/hello_world`, and a JSON file under the path
`data/config.json`. Grouping files into a package is required in order to push
these files to the device.
**[Components][glossary.component]** are the unit of software execution on
Fuchsia. All software on Fuchsia except for the kernel image and user mode
bootstrap program is defined as a component.
A component is defined by a
**[component manifest][glossary.component-manifest]**. Components typically
include additional files, such as executables and data assets that they need at
runtime.
Developers must define their software in terms of packages and components,
whether for building production software or for writing their tests.
At runtime, **[Component instances][glossary.component-instance]** see the
contents of their package as read-only files under the path `/pkg`. Defining two
or more components in the same package doesn't grant each component access to
the other's capabilities. However it can guarantee to one component that the
other is available. Therefore if a component attempts to launch an instance of
another component, such as in an integration test, it can be beneficial to
package both components together.
Components are instantiated in a few ways, all of which somehow specify their
[URL][glossary.component-url]. Typically components are launched by specifying
their package names and path to their component manifest in the package, using
the [<code>fuchsia-pkg://</code> scheme][glossary.fuchsia-pkg-url].
## Component manifests {#component-manifests}
A component manifest is a file that encodes a component declaration, usually
distributed as part of a package. The binary format is a persisted FIDL file
containing the component declaration. The manifest declares information about
the component's program binary and required capabilities.
Below is an example manifest file for a simple "Hello, World" component:
* {.cml}
```json5
{
// Information about the program to run.
program: {
// Use the built-in ELF runner to run native binaries.
runner: "elf",
// The binary to run for this component.
binary: "bin/hello",
// Program arguments
args: [
"Hello",
"World!",
],
},
// Capabilities used by this component.
use: [
{ protocol: "fuchsia.logger.LogSink" },
],
}
```
* {.cmx}
{{ v1_banner }}
```json
{
"program": {
"binary": "bin/hello-world",
"args": [ "Hello", "World!" ]
},
"sandbox": {
"services": [
"fuchsia.logger.LogSink"
]
}
}
```
### Manifest shards {#component-manifest-shards}
Some collections of capabilities represent use case requirements that are common
to many components in the system, such as logging. To simplify including these
capabilities in your components, the Component Framework supports abstracting
them into **manifest shards** that can be included in your main manifest file.
This is conceptually similar to `#include` directives in the C programming
language.
Note: By convention, component manifest shard files are named with `.shard` in
the file suffix.
Below is an equivalent manifest to the previous example, with the logging
capability replaced by a manifest shard `include`:
* {.cml}
```json5
{
// Include capabilities for the syslog library
include: [ "syslog/client.shard.cml" ],
// Information about the program to run.
program: {
// Use the built-in ELF runner to run native binaries.
runner: "elf",
// The binary to run for this component.
binary: "bin/hello-world",
// Program arguments
args: [
"Hello",
"World!",
],
},
}
```
* {.cmx}
{{ v1_banner }}
```json
{
"include": [
"syslog/client.shard.cmx"
],
"program": {
"binary": "bin/hello-world",
"args": [ "Hello", "World!" ]
}
}
```
#### Relative paths
Include paths that begin with `"//"` are relative to the root of the source tree
that you are working in. For include paths that don't begin with `"//"`, the
build system will attempt to resolve them from the Fuchsia SDK.
### Client library includes {#component-manifest-includes}
As shown above, the component manifest supports "include" syntax, which allows
referencing one or more manifest shards as source for additional manifest content.
Some dependencies, such as libraries, assume that dependent components have
certain capabilities available to them at runtime. For instance,
the [C++ Syslog library][cpp-syslog] makes such an assumption.
If you are building a client library, you can declare these required dependencies
using `expect_includes` in your `BUILD.gn` file. For example, consider the
following hypothetical file `//sdk/lib/fonts/BUILD.gn` below:
```gn
import("//tools/cmc/build/expect_includes.gni")
# Client library for components that want to use fonts
source_set("font_provider_client") {
sources = [
"font_provider_client.cc",
...
]
deps = [
":font_provider_client_includes",
...
]
}
expect_includes("font_provider_client_includes") {
includes = [
"client.shard.cmx",
"client.shard.cml",
]
}
```
Note: It recommended to provide both `.cml` and `.cmx` includes until the
[components migration][components-migration] is complete.
This sets a build time requirement for dependent manifests to include the
expected manifest shards:
* {.cml}
```json5
{
include: [
"//sdk/lib/fonts/client.shard.cml",
]
...
}
```
* {.cmx}
{{ v1_banner }}
```json
{
"include": [
"//sdk/lib/fonts/client.shard.cmx"
]
...
}
```
Include paths are resolved relative to the source root.
Transitive includes (includes of includes) are allowed.
Cycles are not allowed.
When naming your shards, don't repeat yourself in relation to the full path.
In the example above it would have been repetitive to name the shard
`fonts.shard.cml` because then the full path would have been
`sdk/lib/fonts/fonts.shard.cml`, which is repetitive. Instead the file is
named `client.shard.cml`, to indicate that it is to be used by clients of the
SDK library for fonts.
## Component package GN templates {#component-package}
[GN][glossary.gn] is the meta-build system used by Fuchsia. Fuchsia extends GN
by defining templates. Templates provide a way to add to GN's built-in target
types.
Fuchsia defines the following GN templates to define packages and components:
* [`fuchsia_component.gni`](/build/components/fuchsia_component.gni)
* [`fuchsia_package.gni`](/build/components/fuchsia_package.gni)
Below is a hypothetical package containing one component that runs a C++
program:
```gn
import("//build/components.gni")
executable("my_program") {
sources = [ "my_program.cc" ]
}
fuchsia_component("my_component") {
manifest = "meta/my_program.cml"
deps = [ ":my_program" ]
}
fuchsia_package("my_package") {
deps = [ ":my_component" ]
}
```
Note the following details:
* Import `"//build/components.gni"` to access all templates related to
packages, components, and tests.
* The `fuchsia_component()` template declares the component. It depends on the
program binary (in this case, `executable()`) and requires a `manifest`
pointing to the component manifest file.
* Both the component and package names are derived from their target names.
In the example above, these names come together to form the URL for
launching the component:
`fuchsia-pkg://fuchsia.com/my_package#meta/my_component.cm`.
Note: Targets support an optional `component_name` or `package_name`
parameter to override the default behavior.
### Language-specific component examples {#language-specific-component-examples}
Below you'll find basic examples for defining a package with a single component
that launches a program in a variety of commonly used languages. The referenced
source files and component manifest are assumed to be present in the specified
paths.
* {C++}
```gn
import("//build/components.gni")
executable("bin") {
output_name = "my_program"
sources = [ "main.cc" ]
}
fuchsia_component("my_component") {
manifest = "meta/my_component.cml"
deps = [ ":bin" ]
}
fuchsia_package("my_package") {
deps = [ ":my_component" ]
}
```
* {Rust}
```gn
import("//build/rust/rustc_binary.gni")
import("//build/components.gni")
rustc_binary("bin") {
output_name = "my_program"
sources = [ "src/main.rs" ]
}
fuchsia_component("my_component") {
manifest = "meta/my_component.cml"
deps = [ ":bin" ]
}
fuchsia_package("my_package") {
deps = [ ":my_component" ]
}
```
* {Go}
```gn
import("//build/go/go_binary.gni")
import("//build/components.gni")
go_binary("bin") {
output_name = "my_program"
sources = [ "main.go" ]
}
fuchsia_component("my_component") {
manifest = "meta/my_component.cml"
deps = [ ":bin" ]
}
fuchsia_package("my_package") {
deps = [ ":my_component" ]
}
```
* {Dart}
```gn
import("//build/dart/dart_component.gni")
import("//build/dart/dart_library.gni")
import("//build/components.gni")
dart_library("lib") {
package_name = "my_lib"
sources = [ "main.dart" ]
}
dart_component("my_component") {
manifest = "meta/my_component.cml"
deps = [ ":lib" ]
}
fuchsia_package("my_package") {
deps = [ ":my_component" ]
}
```
* {Flutter}
```gn
import("//build/dart/dart_library.gni")
import("//build/flutter/flutter_component.gni")
import("//build/components.gni")
dart_library("lib") {
package_name = "my_lib"
sources = [ "main.dart" ]
}
flutter_component("my_component") {
manifest = "meta/my_component.cml"
deps = [ ":lib" ]
}
fuchsia_package("my_package") {
deps = [ ":my_component" ]
}
```
### Packages with a single component {#packages-with-single-component}
Packages are units of distribution. It is beneficial to define multiple
components in the same package if you need to guarantee that several
components are always co-present, or if you'd like to be able to update
several components at once (by updating a single package).
This pattern is also commonly used to create hermetic integration tests.
For instance an integration test between two components where one is a client
of a service implemented in another component would include both the client
and server components.
However, you may often define a package that only requires a single component.
In those cases, you can use the `fuchsia_package_with_single_component()`
template as a convenience. This template fuses together `fuchsia_package()` and
`fuchsia_component()`.
* {C++}
```gn
import("//build/components.gni")
executable("rot13_encoder_decoder") {
sources = [ "rot13_encoder_decoder.cc" ]
}
fuchsia_package_with_single_component("rot13") {
manifest = "meta/rot13.cml"
deps = [ ":rot13_encoder_decoder" ]
}
```
* {Rust}
```gn
import("//build/rust/rustc_binary.gni")
import("//build/components.gni")
rustc_binary("rot13_encoder_decoder") {
sources = [ "src/rot13_encoder_decoder.rs" ]
}
fuchsia_package_with_single_component("rot13") {
manifest = "meta/rot13.cml"
deps = [ ":rot13_encoder_decoder" ]
}
```
* {Go}
```gn
import("//build/go/go_binary.gni")
import("//build/components.gni")
go_binary("rot13_encoder_decoder") {
sources = [ "rot13_encoder_decoder.go" ]
}
fuchsia_package_with_single_component("rot13") {
manifest = "meta/rot13.cml"
deps = [ ":rot13_encoder_decoder" ]
}
```
## Test package GN templates {#test-packages}
Test packages are packages that contain at least one component that is
launched as a test. Test packages are defined using
[`fuchsia_test_package.gni`](/build/components/fuchsia_test_package.gni). This
template can be used to define all sorts of tests, although it's most useful for
integration tests -- tests where other components in addition to the test itself
participate in the test. See [unit tests](#unit-tests) for templates that
specialize in unit testing.
```gn
import("//build/components.gni")
executable("my_test") {
sources = [ "my_test.cc" ]
testonly = true
deps = [
"//src/lib/fxl/test:gtest_main",
"//third_party/googletest:gtest",
]
}
fuchsia_component("my_test_component") {
testonly = true
manifest = "meta/my_test.cml"
deps = [ ":my_test" ]
}
executable("my_program_under_test") {
sources = [ "my_program_under_test.cc" ]
}
fuchsia_component("my_other_component_under_test") {
manifest = "meta/my_component_under_test.cml"
deps = [ ":my_program_under_test" ]
}
fuchsia_test_package("my_integration_test") {
test_components = [ ":my_test_component" ]
deps = [ ":my_other_component_under_test" ]
test_specs = {
environments = [ vim3_env ]
}
}
group("tests") {
deps = [ ":my_integration_test" ]
testonly = true
}
```
Note the following details:
* This example defines `"my_test_component"`, which is assumed to implement
tests written using some common testing framework such as C++ Googletest,
Rust Cargo test, etc.
* The test is packaged with a dependent component,
`"my_other_component_under_test"`. This could be a mock service provider
required by the test component or another component the test needs to invoke.
Packaging these components together guarantees that the dependent component
is available to launch while the test is running, and built at the same
version as the test.
* The `environments` parameter enables `fuchsia_test_package()` to optionally
take [`test_spec.gni`](/build/testing/test_spec.gni) parameters and override
the default testing behavior. In this example, this test is configured to
run on VIM3 devices.
* Finally, this example defines a `group()` to contain all the tests (which we
have exactly one of). This is a [recommended practice][source-code-layout]
for organizing targets across the source tree.
Due to a [limitation in GN][gn-get-target-outputs], any `test_component` targets
in your `fuchsia_test_package()` must be defined in the same `BUILD.gn` file as
the test package target. You can work around this behavior with an indirection
through `fuchsia_test()`.
In one `BUILD.gn` file, define:
```gn
# Let this be //foo/BUILD.gn
import("//build/components.gni")
executable("my_test") {
sources = [ "my_test.cc" ]
testonly = true
deps = [
"//src/lib/fxl/test:gtest_main",
"//third_party/googletest:gtest",
]
}
fuchsia_component("my_test_component") {
testonly = true
manifest = "meta/my_test.cml"
deps = [ ":my_test" ]
}
fuchsia_test("my_test_component_test") {
package = "//bar:my_test_package"
component = ":my_test_component"
}
group("tests") {
testonly = true
deps = [ ":my_test_component_test" ]
}
```
Then elsewhere, you can add the `fuchsia_component()` target to the `deps` of a
`fuchsia_package()` target.
```gn
# Let this be //bar/BUILD.gn
import("//build/components.gni")
fuchsia_package("my_test_package") {
testonly = true
deps = [ "//foo:my_test_component" ]
}
```
### Dart and Flutter tests
Dart and Flutter tests differ slightly in that they need to be built with a
`flutter_test_component()`, which collects all of the test mains into a single
main invocation. The `flutter_test_component()` can then be used by the
`fuchsia_test_package()`.
```gn
import("//build/dart/dart_test_component.gni")
import("//build/flutter/flutter_test_component.gni")
import("//build/components.gni")
flutter_test_component("my_flutter_test_component") {
testonly = true
manifest = "meta/my_flutter_test_component.cml"
sources = [ "foo_flutter_test.dart" ]
}
dart_test_component("my_dart_test_component") {
testonly = true
manifest = "meta/my_dart_test_component.cml"
sources = [ "foo_dart_test.dart" ]
}
fuchsia_test("my_test_component_test") {
test_components = [
":my_dart_test_component",
":my_flutter_test_component"
]
}
```
### Unit tests {#unit-tests}
Since unit tests are very common, the build system provides two simplified
GN templates:
* [`fuchsia_unittest_component.gni`](/build/components/fuchsia_unittest_component.gni)
defines a component to be run as a test, with the option to automatically
generate a basic component manifest, that must then be included in a package.
* [`fuchsia_unittest_package.gni`](/build/components/fuchsia_unittest_package.gni)
defines a package with a single component to be run as a test, shorthand for
a single `fuchsia_unittest_component()` target paired with a
`fuchsia_test_package()`.
#### Unit tests with manifests {#unit-tests-with-manifests}
The examples below demonstrate building a test executable and defining a
package and component for the test.
* {C++}
```gn
import("//build/components.gni")
executable("my_test") {
sources = [ "test.cc" ]
deps = [
"//src/lib/fxl/test:gtest_main",
"//third_party/googletest:gtest",
]
testonly = true
}
fuchsia_unittest_package("my_test") {
manifest = "meta/my_test.cml"
deps = [ ":my_test" ]
}
```
* {Rust}
```gn
import("//build/rust/rustc_test.gni")
import("//build/components.gni")
rustc_test("my_test") {
sources = [ "test.rs" ]
testonly = true
}
fuchsia_unittest_package("my_test") {
manifest = "meta/my_test.cml"
deps = [ ":my_test" ]
}
```
* {Go}
```gn
import("//build/go/go_test.gni")
import("//build/components.gni")
go_test("my_test") {
sources = [ "test.go" ]
testonly = true
}
fuchsia_unittest_package("my_test") {
manifest = "meta/my_test.cml"
deps = [ ":my_test" ]
}
```
Launch the test component using `fx test` with either the GN target name
or the full component URL:
* {GN Target}
```posix-terminal
fx test my_test
```
* {Component URL}
```posix-terminal
fx test fuchsia-pkg://fuchsia.com/my_test#meta/my_test.cm
```
#### Unit tests with _generated_ manifests
The examples above specify a manifest for the test. However, it's possible for
unit tests to not require any particular capabilities.
Below is an example for a test that performs ROT13 encryption and decryption.
The algorithm under test is pure logic that can be tested in complete
isolation. If we were to write a manifest for these tests, it would only
contain the test binary to be executed. In such cases, we can simply specify
the test executable path, and the template generates the trivial manifest
for us.
* {C++}
```gn
import("//build/components.gni")
executable("rot13_test") {
sources = [ "rot13_test.cc" ]
deps = [
"//src/lib/fxl/test:gtest_main",
"//third_party/googletest:gtest",
]
testonly = true
}
fuchsia_unittest_package("rot13_test") {
deps = [ ":rot13_test" ]
}
```
* {Rust}
```gn
import("//build/rust/rustc_test.gni")
import("//build/components.gni")
rustc_test("rot13_test") {
sources = [ "rot13_test.rs" ]
testonly = true
}
fuchsia_unittest_package("rot13_test") {
deps = [ ":rot13_test" ]
}
```
* {Go}
```gn
import("//build/go/go_test.gni")
import("//build/components.gni")
go_test("rot13_test") {
sources = [ "rot13_test.go" ]
testonly = true
}
fuchsia_unittest_package("rot13_test") {
deps = [ ":rot13_test" ]
}
```
Note: By default these templates generate Components V2 (.cml) manifests.
You may pass `v2 = false` to either `fuchsia_unittest_component` or
`fuchsia_unittest_package` to generate a V1 (.cmx) manifest instead.
The generated component manifest file can be found with the following command:
```posix-terminal
fx gn outputs $(fx get-build-dir) {{ '<var>unittest target</var>' }}_generated_manifest
```
To print it directly:
```posix-terminal
fx build && cat $(fx get-build-dir)/$(fx gn outputs $(fx get-build-dir) {{ '<var>unittest target</var>' }}_generated_manifest)
```
Note: `fx gn outputs` prints an output path, but the file at the path
may not exist or may be stale if you haven't built.
Launch the test component using `fx test` with either the GN target name
or the full component URL:
* {GN Target}
```posix-terminal
fx test rot13_test
```
* {Component URL}
```posix-terminal
fx test fuchsia-pkg://fuchsia.com/rot13_test#meta/rot13_test.cm
```
#### Multiple unit tests in a single package
To package multiple unit testing components together, use the
`fuchsia_unittest_component()` rule instead of `fuchsia_unittest_package()`,
collecting them together in a`fuchsia_test_package()`. This enables you to run
all the test components in a single package with `fx test <package_name>` rather
than executing them individually.
The example below creates a single test package `rot13_tests` that contains two
separate test components, `rot13_decoder_test` and `rot13_encoder_test`.
* {C++}
```gn
import("//build/components.gni")
executable("rot13_decoder_bin_test") {}
executable("rot13_encoder_bin_test") {}
fuchsia_unittest_component("rot13_decoder_test") {
deps = [ ":rot13_decoder_bin_test" ]
}
fuchsia_unittest_component("rot13_encoder_test") {
deps = [ ":rot13_encoder_bin_test" ]
}
fuchsia_test_package("rot13_tests") {
test_components = [
":rot13_decoder_test",
":rot13_encoder_test",
]
}
```
* {Rust}
```gn
import("//build/rust/rustc_test.gni")
import("//build/components.gni")
rustc_test("rot13_decoder_bin_test") {}
rustc_test("rot13_encoder_bin_test") {}
fuchsia_unittest_component("rot13_decoder_test") {
deps = [ ":rot13_decoder_bin_test" ]
}
fuchsia_unittest_component("rot13_encoder_test") {
deps = [ ":rot13_encoder_bin_test" ]
}
fuchsia_test_package("rot13_tests") {
test_components = [
":rot13_decoder_test",
":rot13_encoder_test",
]
}
```
* {Go}
```gn
import("//build/go/go_test.gni")
import("//build/components.gni")
go_test("rot13_decoder_test") {}
go_test("rot13_encoder_test") {}
fuchsia_unittest_component("rot13_decoder_test") {
deps = [ ":rot13_decoder_bin_test" ]
}
fuchsia_unittest_component("rot13_encoder_test") {
deps = [ ":rot13_encoder_bin_test" ]
}
fuchsia_test_package("rot13_tests") {
test_components = [
":rot13_decoder_test",
":rot13_encoder_test",
]
}
```
Launch all test components inside the package using `fx test` with simply the
GN target name:
```posix-terminal
fx test rot13_tests
```
### Test-driven development
The `fx smoke-test` command automatically detects all tests that are known to
the build system as affected by changes in your checkout. Try the following:
```posix-terminal
fx -i smoke-test --verbose
```
In the command above, `--verbose` prints which tests `fx smoke-test` thinks
are affected by your change, and `-i` automatically repeats this command
every time you save your changes. For test-driven development, try launching
this command in a separate shell and watching your code rebuild and retest as
you're working on it.
`fx smoke-test` works best with hermetic test packages. A test package is
hermetic if the package contains all the dependencies of any tests in it.
That is to say, any code changes that affect the outcome of this test should
require rebuilding that test's package as well.
## Additional packaged resources {#additional-packaged-resources}
In the examples above we've demonstrated that a `deps` path from a package to a
target that produces an executable ensures that the executable is included in
the package.
Sometimes there is the need to include additional files. Below we demonstrate
the use of two [`resource.gni`](/build/dist/resource.gni) templates,
`resource()` and `resource_group()`.
### Example: fonts
{# Disable variable substitution to avoid {{ being interpreted by the template engine #}
{% verbatim %}
```gn
import("//build/components.gni")
resource("roboto_family") {
sources = [
"Roboto-Black.ttf",
"Roboto-Bold.ttf",
"Roboto-Light.ttf",
"Roboto-Medium.ttf",
"Roboto-Regular.ttf",
"Roboto-Thin.ttf",
]
outputs = [ "data/fonts/{{source_file_part}}" ]
}
fuchsia_component("text_viewer") {
...
deps = [
":roboto_family",
...
]
}
```
{# Re-enable variable substitution #}
{% endverbatim %}
In the example above, six files are provided to be packaged under `data/fonts/`,
producing the paths `data/fonts/Roboto-Black.ttf`,
`data/fonts/Roboto-Bold.ttf`, etc'. The format for `destination` accepts [GN
source expansion placeholders][source-expansion-placeholders].
Then, a text viewer component is defined to depend on the fonts. In this
example, the text viewer implementation renders text with Roboto fonts. The
component can read the given fonts in its sandbox under the path
`/pkg/data/fonts/...`.
### Example: integration test with golden data
In this example we define a hypothetical service that minifies JSON files. The
service is said to receive a buffer containing JSON text, and returns a buffer
containing the same JSON data but with less whitespace. We present an
integration test where a test component acts as the client of the minifier
component, and compares the result for a given JSON file to be minified against
a known good result (or a "golden file").
{# Disable variable substitution to avoid {{ being interpreted by the template engine #}
{% verbatim %}
```gn
import("//build/components.gni")
fuchsia_component("minifier_component") {
...
}
fuchsia_package("minifier_package") {
...
}
resource("testdata") {
sources = [
"testdata/input.json",
"testdata/input_minified.json",
]
outputs = [ "data/{{source_file_part}}" ]
}
fuchsia_component("minifier_test_client") {
testonly = true
deps = [
":testdata",
...
]
...
}
fuchsia_test_package("minifier_integration_test") {
test_components = [ ":minifier_test_client" ]
deps = [ ":minifier_component" ]
}
```
{# Re-enable variable substitution #}
{% endverbatim %}
Note that we place the `resource()` dependency on the test component. From the
build system's perspective the resource dependency could have been placed on
the test package and the same outcome would have been produced by the build.
However, it is a better practice to put dependencies on the targets that need
them. This way we could reuse the same test component target in a different
test package, for instance to test against a different minifier component, and
the test component would work the same.
### Example: using `resource_group()`
In the examples above all the paths conformed to a certain structure such that
we could specify a single output pattern for multiple files and even leverage
[GN source expansion placeholders][source-expansion-placeholders]. In this next
example we are required to rename different files to different destination
paths for packaging.
```gn
import("//build/components.gni")
resource_group("favorite_recipes") {
files = [
{
source = "//recipes/spaghetti_bolognese.txt"
dest = "data/pasta/spaghetti_bolognese.txt"
},
{
source = "//recipes/creamy_carbonara.txt"
dest = "data/pasta/carbonara.txt"
},
{
source = "//recipes/creme_brulee.txt"
dest = "data/dessert/creme_brulee.txt"
},
...
]
}
```
Our sources are all in a single directory, but are to be packaged in different
directories, some even under different names. To express this same relationship
we might need as many `resource()` targets as we have files. Situations like
this call for the use of `resource_group()` instead, as shown above.
The underlying behavior of `resource()` and `resource_group()` is identical.
You are free to choose whichever one you prefer.
Note: see more information in [provide data files to components][provide-data].
## Restricted features {#restricted-features}
When a new component manifest feature is under active development, or a feature
is intended for a narrow audience, the Component Framework team may wish to
restrict who may use the feature. The CML compiler (`cmc`) controls access to
these restricted features through an opt-in property in your component build
rule.
In order to use an restricted feature, add the `restricted_features` property:
```gn
fuchsia_component("my-component") {
manifest = "meta/my-component.cml"
# This component opts-in to the restricted "allow_long_names" feature.
restricted_features = [ "allow_long_names" ]
deps = [ ... ]
}
```
Use of restricted features are restricted to an allowlist.
You must add your component to the allowlist for the feature in
[`//tools/cmc/build/restricted_features/BUILD.gn`][allowlist].
## Troubleshooting {#troubleshooting}
This section contains common issues you may encounter while building your components.
### Missing shard includes {#troubleshoot-build-include}
The `check_includes` action fails the build with the following error if your
[component manifest][glossary.component-manifest] is missing an `include` for a
required [manifest shard](#component-manifest-shards):
```none {:.devsite-disable-click-to-copy}
Error at ../../examples/components/echo_server/meta/echo_server.cml:
"../../examples/components/echo_server/meta/echo_server.cml" must include "../../sdk/lib/inspect/client.shard.cml".
```
This occurs when a library in your component's dependency chain has an
[`expect_includes`](#component-manifest-includes) requirement and the required
`include` was not found in your component manifest. Consider the following example
using [Inspect][doc-inspect]:
* {C++}
1. Your component depends on `//sdk/lib/sys/inspect/cpp`:
```gn {:.devsite-disable-click-to-copy}
executable("bin") {
output_name = "echo_server_cpp"
sources = [ "main.cc" ]
deps = [
"//examples/components/routing/fidl:echo",
"//sdk/lib/sys/cpp",
{{ '<strong>' }}# This library requires "inspect/client.shard.cml" {{ '</strong>' }}
{{ '<strong>' }}"//sdk/lib/sys/inspect/cpp", {{ '</strong>' }}
"//zircon/system/ulib/async-loop:async-loop-cpp",
"//zircon/system/ulib/async-loop:async-loop-default",
]
}
```
1. [`//sdk/lib/sys/inspect/cpp`][src-inspect-cpp] depends on
[`//sdk/lib/inspect:client_includes`][src-inspect-include], which is an
`expect_includes()` rule.
* {Rust}
1. Your component depends on `//src/lib/diagnostics/inspect/runtime/rust`:
```gn
rustc_binary("echo_server") {
edition = "2018"
deps = [
"//examples/components/routing/fidl:echo-rustc",
{{ '<strong>' }}# This library requires "inspect/client.shard.cml" {{ '</strong>' }}
{{ '<strong>' }}"//src/lib/diagnostics/inspect/runtime/rust", {{ '</strong>' }}
"//src/lib/diagnostics/inspect/rust",
"//src/lib/fuchsia",
"//src/lib/fuchsia-component",
"//third_party/rust_crates:anyhow",
"//third_party/rust_crates:futures",
]
sources = [ "src/main.rs" ]
}
```
1. [`//src/lib/diagnostics/inspect/runtime/rust`][src-inspect-rust] depends on
[`//sdk/lib/inspect:client_includes`][src-inspect-include], which is an
`expect_includes()` rule.
To address the issue, add the missing `include` in your component manifest. For example:
```json5 {:.devsite-disable-click-to-copy}
{
include: [
{{ '<strong>' }}// Add this required include {{ '</strong>' }}
{{ '<strong>' }}"inspect/client.shard.cml", {{ '</strong>' }}
// Enable logging on stdout
"syslog/elf_stdio.shard.cml",
],
// ...
}
```
For additional detail on the source of the required includes, you can use the `gn path`
command to explore the dependency path:
```posix-terminal
fx gn path $(fx get-build-dir) {{ '<var>my-component</var>' }} {{ '<var>expect_includes target</var>' }} --with-data
```
Note: You can find the `expect_includes()` target by searching for `BUILD.gn` files that
reference the missing shard by filename.
The command prints output similar to the following, showing the path to the library that
required the include:
* {C++}
```none {:.devsite-disable-click-to-copy}
$ fx gn path $(fx get-build-dir) //examples/components/routing/cpp/echo_server //sdk/lib/inspect:client_includes --with-data
//examples/components/echo_server:bin --[private]-->
//sdk/lib/sys/inspect/cpp:cpp --[data]-->
//sdk/lib/inspect:client_includes
```
* {Rust}
```none {:.devsite-disable-click-to-copy}
$ fx gn path $(fx get-build-dir) //examples/components/routing/rust/echo_server //sdk/lib/inspect:client_includes --with-data
//examples/components/routing/rust/echo_server:echo_server --[public]-->
//examples/components/routing/rust/echo_server:echo_server.actual --[private]-->
//src/lib/diagnostics/inspect/runtime/rust:rust --[public]-->
//src/lib/diagnostics/inspect/runtime/rust:lib --[public]-->
//src/lib/diagnostics/inspect/runtime/rust:lib.actual --[private]-->
//sdk/lib/inspect:client_includes
```
### Failed to validate manifest {#troubleshoot-build-references}
The `cmc_validate_references` action fails the build with the following error if your
[component manifest][glossary.component-manifest] contains references to resources that
cannot be found in the component's package:
```none {:.devsite-disable-click-to-copy}
Error found in: //examples/components/echo/rust:rust-component_cmc_validate_references(//build/toolchain/fuchsia:x64)
Failed to validate manifest: "obj/examples/components/echo/rust/cml/rust-component_manifest_compile/echo_rust.cm"
program.binary=bin/echo_example_oops but bin/echo_example_oops is not provided by deps!
Did you mean bin/echo_example?
Try any of the following:
...
```
This occurs when the `binary` field in your component manifest [`program`][cml-program] block
references a file path that is not present in your `fuchsia_package()`.
To address the issue, verify the following:
1. Reference paths in your component manifest are entered correctly.
```json5 {:.devsite-disable-click-to-copy}
{
// ...
// Information about the program to run.
program: {
// Use the built-in ELF runner.
runner: "elf",
{{ '<strong>' }}// The binary to run for this component. {{ '</strong>' }}
{{ '<strong>' }}binary: "bin/echo_example_oops", {{ '</strong>' }}
},
}
```
1. The component executable target is part of the `deps` chain connected to your
`fuchsia_package()`:
* {C++}
```gn {:.devsite-disable-click-to-copy}
executable("bin") {
output_name = "echo_example"
sources = [ "main.cc" ]
deps = [ ... ]
}
{{ '<strong>' }}# Neither the component or package depend on ":bin" {{ '</strong>' }}
fuchsia_component("component") {
manifest = "meta/echo_example.cml"
{{ '<strong>' }}deps = [] {{ '</strong>' }}
}
fuchsia_package("package") {
package_name = "echo_example"
{{ '<strong>' }}deps = [ ":component" ] {{ '</strong>' }}
}
```
* {Rust}
```gn
rustc_binary("echo_example") {
edition = "2018"
sources = [ "src/main.rs" ]
deps = [ ... ]
}
{{ '<strong>' }}# Neither the component or package depend on ":echo_example" {{ '</strong>' }}
fuchsia_component("component") {
manifest = "meta/echo_example.cml"
{{ '<strong>' }}deps = [] {{ '</strong>' }}
}
fuchsia_package("package") {
package_name = "echo_example"
{{ '<strong>' }}deps = [ ":component" ] {{ '</strong>' }}
}
```
### Static capability analyzer {#troubleshoot-build-analyzer}
The Scrutiny static analyzer fails the build with the following error when it is unable
to verify each the [capability routes][glossary.capability-routing] in the
[component topology][glossary.component-topology]:
```none {:.devsite-disable-click-to-copy}
Static Capability Flow Analysis Error:
The route verifier failed to verify all capability routes in this build.
...
Verification Errors:
[
{
"capability_type": "directory",
"results": { ... }
},
{
"capability_type": "protocol",
"results": { ... }
},
]
```
This occurs when the analyze cannot successfully trace a capability route from its source
to the component requesting the capability through a valid chain of [`expose`][cml-expose]
and [`offer`][cml-offer] component manifest declarations.
In the following example, the error occurs due to the component `/core/echo` requesting to
`use` the `fuchsia.logger.LogSink` protocol without a corresponding `offer` for that capability
from the parent:
```none {:.devsite-disable-click-to-copy}
"errors": [
{
"using_node": "/core/echo",
"capability": "fuchsia.logger.LogSink",
"error": {
"error": {
"analyzer_model_error": {
"routing_error": {
"use_from_parent_not_found": {
"moniker": {
"path": [
{
"name": "core",
"collection": null,
"rep": "core"
},
{
"name": "echo",
"collection": null,
"rep": "echo"
}
]
},
"capability_id": "fuchsia.logger.LogSink"
}
}
}
},
"message": "A `use from parent` declaration was found at `/core/echo` for `fuchsia.logger.LogSink`, but no matching `offer` declaration was found in the parent"
}
}
]
```
To address this issue explore the error details provided in the build failure to discover the
source of the routing error, then add or correct the invalid declarations in the routing chain.
In the previous example error, an `offer` should be added in the parent component's manifest:
```json5
{
// ...
children: [
// ...
{
name: "echo",
url: "#meta/echo.cm",
},
],
offer: [
// ...
{{ '<strong>' }}{ {{ '</strong>' }}
{{ '<strong>' }}protocol: "fuchsia.logger.LogSink", {{ '</strong>' }}
{{ '<strong>' }}from: "parent", {{ '</strong>' }}
{{ '<strong>' }}to: "#echo", {{ '</strong>' }}
{{ '<strong>' }}}, {{ '</strong>' }}
],
}
```
For more details on building capability routes, see [Connect components][doc-connect].
[allowlist]: /tools/cmc/build/restricted_features/BUILD.gn
[cml-expose]: https://fuchsia.dev/reference/cml#expose
[cml-offer]: https://fuchsia.dev/reference/cml#offer
[cml-program]: https://fuchsia.dev/reference/cml#program
[components-migration]: /docs/contribute/open_projects/components/migration.md
[cpp-syslog]: /docs/development/languages/c-cpp/logging.md#component_manifest_dependency
[doc-connect]: /docs/development/components/connect.md
[doc-inspect]: /docs/development/diagnostics/inspect/README.md
[executable]: https://gn.googlesource.com/gn/+/HEAD/docs/reference.md#func_executable
[ffx-scrutiny]: https://fuchsia.dev/reference/tools/sdk/ffx#scrutiny
[fx-test]: https://fuchsia.dev/reference/tools/fx/cmd/test.md
[fxb-55739]: https://bugs.fuchsia.dev/p/fuchsia/issues/detail?id=55739
[glossary.capability-routing]: /docs/glossary/README.md#capability-routing
[glossary.component]: /docs/glossary/README.md#component
[glossary.component-instance]: /docs/glossary/README.md#component-instance
[glossary.component-manifest]: /docs/glossary/README.md#component-manifest
[glossary.component-topology]: /docs/glossary/README.md#component-topology
[glossary.component-url]: /docs/glossary/README.md#component-url
[glossary.fuchsia-pkg-url]: /docs/glossary/README.md#fuchsia-pkg-url
[glossary.gn]: /docs/glossary/README.md#gn
[glossary.package]: /docs/glossary/README.md#fuchsia-package
[gn-get-target-outputs]: https://gn.googlesource.com/gn/+/HEAD/docs/reference.md#func_get_target_outputs
[provide-data]: /docs/development/components/data.md
[rustc-binary]: /build/rust/rustc_binary.gni
[rustc-test]: /build/rust/rustc_test.gni
[source-code-layout]: /docs/development/source_code/layout.md
[source-expansion-placeholders]: https://gn.googlesource.com/gn/+/HEAD/docs/reference.md#placeholders
[src-inspect-cpp]: /sdk/lib/sys/inspect/cpp/BUILD.gn
[src-inspect-include]: /sdk/lib/inspect/BUILD.gn
[src-inspect-rust]: /src/lib/diagnostics/inspect/runtime/rust/BUILD.gn
[test-environments]: /docs/contribute/testing/environments.md
[v2-test-component]: /docs/development/testing/components/test_component.md
[working-with-packages]: /docs/development/idk/documentation/packages.md