Skip to content

Latest commit

 

History

History
1417 lines (1114 loc) · 41.3 KB

File metadata and controls

1417 lines (1114 loc) · 41.3 KB

{% set v1_banner %}

Caution: Caution: This format is used with legacy components. If you are still using legacy components, consider migrating to the modern component framework. {% 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 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 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. 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 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. Typically components are launched by specifying their package names and path to their component manifest in the package, using the fuchsia-pkg:// scheme.

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}

    {
        // 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 }}

    {
        "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}

    {
        // 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 }}

    {
        "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 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:

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 is complete.

This sets a build time requirement for dependent manifests to include the expected manifest shards:

  • {.cml}

    {
        include: [
            "//sdk/lib/fonts/client.shard.cml",
        ]
        ...
    }
  • {.cmx}

    {{ v1_banner }}

    {
        "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 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:

Below is a hypothetical package containing one component that runs a C++ program:

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++}
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}
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}
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}
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}
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++}
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}
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}
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. 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 for templates that specialize in unit testing.

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 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 for organizing targets across the source tree.

Due to a limitation in GN, 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:

# 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.

# 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().

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 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 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++}
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}
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}
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}
fx test my_test
  • {Component URL}
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++}
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}
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}
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:

fx gn outputs $(fx get-build-dir) {{ '<var>unittest target</var>' }}_generated_manifest

To print it directly:

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}
fx test rot13_test
  • {Component URL}
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 afuchsia_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++}
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}
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}
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:

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:

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 templates, resource() and resource_group().

Example: fonts

{# Disable variable substitution to avoid {{ being interpreted by the template engine #} {% verbatim %}

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.

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 %}

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. In this next example we are required to rename different files to different destination paths for packaging.

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.

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:

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.

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 is missing an include for a required manifest shard:

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 requirement and the required include was not found in your component manifest. Consider the following example using Inspect:

  • {C++}

    1. Your component depends on //sdk/lib/sys/inspect/cpp:

      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",
        ]
      }
    2. //sdk/lib/sys/inspect/cpp depends on //sdk/lib/inspect:client_includes, which is an expect_includes() rule.

  • {Rust}

    1. Your component depends on //src/lib/diagnostics/inspect/runtime/rust:

      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" ]
      }
    2. //src/lib/diagnostics/inspect/runtime/rust depends on //sdk/lib/inspect:client_includes, which is an expect_includes() rule.

To address the issue, add the missing include in your component manifest. For example:

{
    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:

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++}

    $ 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}

    $ 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 contains references to resources that cannot be found in the component's package:

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 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.

    {
        // ...
    
        // 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>' }}
        },
    }
  2. The component executable target is part of the deps chain connected to your fuchsia_package():

    • {C++}

      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}

      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 in the component topology:

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 and 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:

"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:

{
    // ...

    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.