blob: a5e3de75dfabbb906fa88bfe6c88ebdd259a98ed [file] [log] [blame] [view] [edit]
# Provide data files to components
## Goal
In the guide on [building components][build-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.
{# note: the verbatim tags below are to avoid issues with the fuchsia.dev template engine #}
```gn
import("//build/dist/resource.gni")
{% verbatim %}
# List of greetings
resource("greetings") {
sources = [ "greetings.txt" ]
outputs = [ "data/{{source_file_part}}" ]
}{% endverbatim %}
```
See the [resource][resource] template for more usage instructions.
For information about `{% verbatim %}{{source_file_part}}{% endverbatim %}`
and similar syntax see [GN placeholders][gn-placeholders]{:.external}.
Using `resource()` is also demonstrated in [additional packaged resources][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.
```gn
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][metafar],
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.
```gn
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.
## Product-specific configuration with `config_data()`
Sometimes a component is defined in one repository but its data is defined in
another repository. For instance `fuchsia.git` defines a font provider service,
but the `workstation` product configuration (defined in a different repository)
defines which fonts are available to the font provider.
The `config_data()` template allows developers to make files available to
components in a different package without having to directly change the contents
of that package.
{# note: the verbatim tags below are to avoid issues with the fuchsia.dev template engine #}
```gn
import("//build/config.gni")
{% verbatim %}
config_data("workstation_fonts") {
for_pkg = "fonts"
sources = [
"RobotoMono-Light.ttf",
"RobotoMono-Medium.ttf",
"RobotoMono-Regular.ttf",
]
outputs = [ "fonts/{{source_file_part}}" ]
}{% endverbatim %}
```
### Using `config_data()` with a v1 component
Include the following in your component manifest (`.cmx`) file:
```json
{
"sandbox": {
"features": [
"config-data"
]
}
}
```
At runtime your component will be able to read the config files at the path
`/config/data`. In the fonts example above, this assumes that your component
launches from a package named `"fonts"`.
### Using `config_data()` with a v2 component
Include the following in your component manifest (`.cml`) file:
```json5
{
use: [
{
directory: "config-data",
rights: [ "r*" ],
path: "/config/data",
},
],
}
```
At runtime your component will be able to read the config files at the path
`/config/data`.
For the above to work, `"config-data"` must be offered to your component.
For instance your parent may have a declaration that looks like this:
```json5
{
children: [
{
name: "font-provider",
url: "fuchsia-pkg://fuchsia.com/fonts#meta/font-provider.cm",
},
],
offer: [
{
directory: "config-data",
from: "parent",
to: [ "#font-provider" ],
subdir: "fonts",
},
],
}
```
See also [configuration data in the v2 migration guide][config-migration].
### How `config_data()` works
All `config_data()` targets that are defined in your build configuration collect
their files into a single package called `config-data`. This package is defined
in the system assembly as part of the base package set. The contents of this
package replicate the parameters in `config_data()` definitions, so that they
can be routed as subdirectories to components that expect them.
### Known issues
* The `config-data` package that collects all files from `config_data()`
definitions is part of the base set of packages. As a result its contents do
not update in the `fx serve` developer workflow. To update data files you
must repave or OTA your device, or if using an emulator rebuild the system
image and restart the emulator.
* Defining `config_data()` also requires making changes to component manifest
files as shown above. Some of the strings used are repeated in multiple
places, which is error-prone. When mistakes are made they can be difficult
to troubleshoot.
Due to the above, always prefer using `resource()` if possible.
[additional-packaged-resources]: /docs/development/components/build.md#additional-packaged-resources
[build-components]: /docs/development/components/build.md
[config-migration]: /docs/development/components/v2/migration.md#config-data
[gn-placeholders]: https://gn.googlesource.com/gn/+/HEAD/docs/reference.md#placeholders
[metafar]: /docs/concepts/packages/package.md#metafar
[resource]: /build/dist/resource.gni