Provide data files to components

Goal

In the guide on building components we saw several examples of defining components for executables and then packaging them. In this document we review ways of making data files available to components in the same package.

Hermetic data files with resource()

At runtime, components are able to read the contents of their own package by accessing the path /pkg/ in their namespace. The resource() template may be used to add contents to the package that may be accessed this way.

import("//build/dist/resource.gni")

# List of greetings
resource("greetings") {
  sources = [ "greetings.txt" ]
  outputs = [ "data/{{source_file_part}}" ]
}

For information about {{source_file_part}} and similar syntax see GN placeholders.

See resource.gni for more usage instructions on the resource() template, and related templates resource_group() and resource_tree().

More examples using resource(), resource_group(), and resource_tree() can be found in additional packaged resources.

Including resources with a component

Add a dependency on the resource target from a component in order to ensure that the resource(s) are included in the same package.

import("//build/components.gni")

# Sends a random greeting to a client
executable("greeter") {
  sources = [ "greeter.cc" ]
  deps = [ ... ]
}

fuchsia_component("greeting_server") {
  deps = [
    ":greeter",
    ":greetings",
  ]
  manifest = "meta/greeting_server.cml"
}

In the example above, at runtime the component will be able to read the file in its namespace at the path /pkg/data/greetings.txt. This will work regardless of what package(s) (defined with fuchsia_package()) this component is included in.

Packaging conventions

  • Small data files (less than 4kb) should be packaged under meta/, though this is not required. Packaging small files under meta/ allows the packaging system to archive them in a single meta.far file, which is a more efficient way to store small files.

  • Otherwise, data files are usually packaged under data/ by convention, though again this is not a technical requirement.

Using different resources in different packages

Sometimes it's desirable to package the same component with different data files.

import("//build/dist/resource.gni")
import("//build/components.gni")

# Sends a random greeting to a client
executable("greeter") {
  sources = [ "greeter.cc" ]
  deps = [ ... ]
}

fuchsia_component("greeting_server") {
  deps = [ ":greeter" ]
  manifest = "meta/greeting_server.cml"
}

# List of production greetings.
# Contains only the finest greetings and the best regards.
resource("greetings") {
  sources = [ "greetings.txt" ]
  outputs = [ "data/greetings.txt" ]
}

fuchsia_package("greeting") {
  deps = [
    ":greeting_server",
    ":greetings",
  ]
}

# Greetings for testing.
# Contains exactly one greeting so that tests are reproducible.
resource("test_greeting") {
  testonly = true
  sources = [ "test_greeting.txt" ]
  outputs = [ "data/greetings.txt" ]
}

# Connects to the greeting server.
# Ensures that the expected greeting is sent back.
fuchsia_test_component("greeting_test_client") {
  ...
}

fuchsia_test_package("greeting_integration_test") {
  test_components = [ ":greeting_test_client" ]
  deps = [
    ":greeting_server",
    ":test_greeting",
  ]
}

In the example above, the same greeting_server component is added to two packages, one for production and another for testing. In both cases the component will find a file under /pkg/data/greetings.txt. However the contents of this file will vary between the production version and the testing version, depending on the package association.