blob: 1ae5a244242a6e280f86a94d4313684262b9403c [file] [log] [blame] [view]
# Migrating legacy package build rules {#legacy-package-migration}
Note: this migration is complete! The guide below is kept for archival
purposes.
This document provides instructions on migrating the component build rules in
your `BUILD.gn` files from the legacy [`package()`] template
to the new [`fuchsia_package()`](/build/components/fuchsia_package.gni).
For more details on using the new component build rules, see the
[Build components][build-components] developer guide.
## Migration examples
The examples below demonstrate some common migration scenarios.
### Simple `package()` example
This example is adapted from
[`//src/sys/component_index/BUILD.gn`](/src/sys/component_index/BUILD.gn).
* {Pre-migration}
```gn
import("//build/config.gni")
import("//build/package.gni") # <1>
import("//build/rust/rustc_binary.gni")
import("//build/test/test_package.gni") # <1>
rustc_binary("component_index_bin") { # <2>
name = "component_index"
# Generate a ":bin_test" target for unit tests
with_unit_tests = true
edition = "2018"
deps = [ ... ]
}
package("component_index") { # <3>
deps = [ ":component_index_bin" ]
binaries = [
{
name = "component_index"
},
]
meta = [
{
path = rebase_path("meta/component_index.cmx") # <4>
dest = "component_index.cmx" # <4>
},
]
resources = [ ... ]
}
test_package("component_index_tests") { # <5>
deps = [ ":component_index_bin_test" ]
tests = [
{
name = "component_index_bin_test" # <5>
dest = "component_index_tests" # <5>
},
]
}
```
* {Post-migration}
```gn
import("//build/config.gni")
import("//build/rust/rustc_binary.gni")
import("//build/components.gni") # <1>
rustc_binary("component_index_bin") { # <2>
name = "component_index"
# Generate a ":bin_test" target for unit tests
with_unit_tests = true
edition = "2018"
deps = [ ... ]
}
fuchsia_package_with_single_component("component_index") { # <3>
manifest = "meta/component_index.cmx" # <4>
deps = [ ":component_index_bin" ]
}
fuchsia_unittest_package("component_index_tests") { # <5>
deps = [ ":component_index_bin_test" ]
}
```
The following key elements are called out in the code example above:
> 1. Necessary imports are replaced by `//build/components.gni`.
> 2. Targets that generate executables or data files are not expected to change
> in a migration.
> 3. The original `package()` declaration contains a single component manifest
> (listed under `meta`). The `fuchsia_package_with_single_component()`
> template can replace this, referencing the same manifest file.
> 4. Under `package()`, the manifest is given a specific destination
> (`"component_index.cmx"`) to place it in the final package. With the new
> templates, the manifest is renamed according to the **target name**.
> As a result, the launch URL for the component remains the same.
> 5. For a simple test package that does not contain multiple test components,
> the `fuchsia_unittest_package()` template replaces `test_package()`. A
> basic test component manifest is automatically generated and
> `meta/component_index_tests.cmx` is no longer needed.
### Complex `package()` example
This example is adapted from
[`//src/fonts/BUILD.gn`](/src/fonts/BUILD.gn).
* {Pre-migration}
```gn
import("//build/package.gni") # <1>
import("//build/rust/rustc_binary.gni")
import("//build/test/test_package.gni") # <1>
import("//src/fonts/build/fonts.gni")
rustc_binary("font_provider") { # <2>
name = "font_provider"
# Generate a ":bin_test" target for unit tests
with_unit_tests = true
edition = "2018"
deps = [ ... ]
sources = [ ... ]
}
package("pkg") {
package_name = "fonts"
deps = [ ":font_provider" ]
binaries = [
{
name = "font_provider"
},
]
meta = [ # <3>
{
path = rebase_path("meta/fonts.cmx") # <3>
dest = "fonts.cmx" # <4>
},
{
path = rebase_path("meta/fonts.cml") # <3>
dest = "fonts.cm" # <4>
},
]
}
test_package("font_provider_unit_tests") {
deps = [ ":font_provider_test" ]
v2_tests = [
{
name = "font_provider_bin_test" # <4>
},
]
}
```
* {Post-migration}
```gn
import("//build/rust/rustc_binary.gni")
import("//src/fonts/build/fonts.gni")
import("//build/components.gni") # <1>
rustc_binary("font_provider") { # <2>
name = "font_provider"
# Generate a ":bin_test" target for unit tests
with_unit_tests = true
edition = "2018"
deps = [ ... ]
sources = [ ... ]
}
fuchsia_component("font_provider_cm") { # <3>
manifest = "meta/fonts.cml"
component_name = "fonts" # <4>
deps = [ ":font_provider" ]
}
fuchsia_component("font_provider_cmx") { # <3>
manifest = "meta/fonts.cmx"
component_name = "fonts" # <4>
deps = [ ":font_provider" ]
}
fuchsia_package("pkg") {
package_name = "fonts"
deps = [
":font_provider_cm", # <3>
":font_provider_cmx", # <3>
]
}
fuchsia_component("font_provider_unit_tests_cmp") {
testonly = true
manifest = "meta/font_provider_bin_test.cml"
component_name = "font_provider_bin_test" # <4>
deps = [ ":font_provider_test" ]
}
fuchsia_test_package("font_provider_unit_tests") {
test_components = [ ":font_provider_unit_tests_cmp" ]
}
```
The following key elements are called out in the code example above:
> 1. Necessary imports are replaced by `//build/components.gni`.
> 2. Targets that generate executables or data files are not expected to change
> in a migration.
> 3. If a `package()` includes multiple distinct components using the `meta`
> field, each one must be broken out into a separate `fuchsia_component()`
> and collected together in the `fuchsia_package()` using `deps`.
> 4. Each `fuchsia_component()` uses the `component_name` field to map the
> manifest destination in the final package. Without this, they are placed
> according to the **target name**, which affects the launch URL of the
> component.
> This is true for both `fuchsia_package()` and `fuchsia_test_package()`.
Note: The new build templates allow targets that produce files, such as
`executable()`, to decide which files they produce and where the targets place
these files. This may affect the packaged path to binaries in your manifest or
test definition after migrating. If you encounter build-time errors you are
unable to resolve, see [Troubleshooting](#troubleshooting).
## Test package considerations
The example below highlights some key differences between the legacy
[`test_package()`] template and the new
[`fuchsia_test_package()`](/build/components/fuchsia_test_package.gni).
* {Pre-migration}
```gn
import("//build/package.gni") # <1>
import("//build/test/test_package.gni") # <1>
executable("foo_bin_test") { ... }
test_package("foo_tests") { # <1>
deps = [ ":foo_bin_test" ] # <2>
tests = [ # <3>
{
name = "foo_test" # <2>
log_settings = {
max_severity = "ERROR"
}
}
]
}
```
* {Post-migration}
```gn
import("//build/components.gni") # <1>
executable("foo_bin_test") { ... }
fuchsia_component("foo_test") { # <2>
testonly = true
manifest = "meta/foo_test.cmx"
deps = [ ":foo_bin_test" ]
}
fuchsia_test_package("foo_tests") { # <1>
test_components = [ ":foo_test" ] # <2>
test_specs = { # <3>
log_settings = {
max_severity = "ERROR"
}
}
}
```
The following key elements are called out in the code example above:
> 1. Replace necessary imports with `//build/components.gni` and rename
> `test_package()` to `fuchsia_test_package()`.
> 2. Create a `fuchsia_component()` to encapsulate the test components previously
> added with the `tests` field. Reference the components in the package with
> the new `test_components` field.
>
> Note: A `test_package()` typically sets the packaged path for binaries to
> `test/`, while the new build rules let the executables define this and they
> typically use `bin/`. This may affect the packaged path to binaries in your
> test definition after migrating. If you encounter build-time errors you are
> unable to resolve, see [Troubleshooting](#troubleshooting).
>
> 3. Both template families support test specifications, such as restricting to
> specific [test environments][test-environments] or
> [restricting log severity][restrict-log-severity].
>
> Note: With the new templates, the `test_specs` apply to all tests in the package.
> See [test packages](#test-packages) for more examples.
## Remove legacy allowlist
The `deprecated_package` group in [`//build/BUILD.gn`](/build/BUILD.gn) contains
an allowlist of build files still using the legacy `package()` template.
Once you have successfully migrated your build files to the new templates,
remove the affected lines from the group. Removing the allowlist entries prevents
future changes from re-introducing uses of the legacy templates.
For example, if you migrated the files under [`//src/fonts`](/src/fonts) to the
new templates, you would find and remove all the related files paths in
[`//build/BUILD.gn`](/build/BUILD.gn):
```gn
group("deprecated_package") {
...
visibility += [
...
"//src/fonts/*",
"//src/fonts/char_set/*",
"//src/fonts/font_info/*",
"//src/fonts/manifest/*",
"//src/fonts/offset_string/*",
"//src/fonts/tests/integration/*",
"//src/fonts/tests/smoke/*",
...
]
}
```
## Troubleshooting {#troubleshooting}
### Listing the contents of a package {#listing-the-contents-of-a-package}
Packages are described by a package manifest, which is a text file where every
line follows this structure:
```
<packaged-path>=<source-file-path>
```
To find the package manifest for a `fuchsia_package()` or
`fuchsia_test_package()` target, use the following command:
<pre class="prettyprint">
<code class="devsite-terminal">fx gn outputs out/default <var>package target</var>_manifest</code>
</pre>
The package target is a fully-qualified target name, i.e. in the form
`//path/to/your:target`.
Combine this with another command to print the package manifest:
<pre class="prettyprint">
<code class="devsite-terminal">cat out/default/$(fx gn outputs out/default <var>package target</var>_manifest)</code>
</pre>
See also:
* [Working with packages][working-with-packages]
* [Fuchsia Package Manager][pm]
### Finding paths for built executables {#finding-paths-for-built-executables}
Executable programs can be built with various language-specific templates such
as `executable()`, `rustc_binary()`, `go_binary()` etc'. These templates are
responsible for specifying where in a package their output binaries should be
included. The details vary by runtime and toolchain configuration.
* Typically the path is `bin/` followed by the target's name.
* Typically if an `output_name` or `name` is specified, it overrides the
target name.
Some rudimentary examples are given below:
* {C++}
```gn
# Binary is packaged as `bin/rot13_encode`
executable("rot13_encode") {
sources = [ "main.cc" ]
}
```
* {Rust}
```gn
# Binary is packaged as `bin/rot13_encode`
rustc_binary("rot13_encode") {}
```
* {Go}
```gn
# Binary is packaged as `bin/rot13_encode`
go_binary("rot13_encode") {}
```
In order to reference an executable in a component manifest, the author needs
to know its packaged path.
One way to find the packaged path for an executable is to make sure that the
target that builds the executable is in a package's `deps`, then follow
[listing the contents of a package](#listing-the-contents-of-a-package).
The executable is listed among the contents of the package.
### Finding a component's launch URL
Component URLs follow this pattern:
```none
fuchsia-pkg://fuchsia.com/<package-name>#meta/<component-name>.<extension>
```
* `<package-name>`: specified as `package_name` on the package target, which
defaults to the target name.
* `<component-name>`: specified as `component_name` on the component target,
which defaults to the target name.
* `<extension>`: based on the [component manifest][glossary.component-manifest];
`cmx` for CMX files, `cm` for CML files.
## Legacy features
The following special attributes are supported by the legacy `package()` template:
* `binaries`
* `drivers`
* `libraries`
* `loadable_modules`
These are used with special syntax, which determines how the files that certain
targets produce are packaged.
For instance the `libraries` attribute installs resources in a special `lib/` directory,
`drivers` are installed in `drivers/`, etc'.
The legacy syntax looks like this:
```
package("my_driver_package") {
deps = [ ":my_driver" ]
drivers = [
{
name = "my_driver.so"
},
]
}
```
This special treatment is not necessary with the new templates. Simply add the
necessary target to `deps = [ ... ]` and the packaging is done automatically.
```
fuchsia_component("my_driver_component") {
deps = [ ":my_driver" ]
...
}
fuchsia_package("my_driver_package") {
deps = [ ":my_driver_component" ]
...
}
```
Additionally, legacy `package()` supports the `resources` attribute. This is
replaced by adding a dependency on a `resource()` target.
For more details, see [Provide data files to components][resource-data].
## Renaming files
The legacy `package()` template allowed developers to rename certain files that
are included in their package. For example, below we see an executable being
built and then renamed before its packaged so that its packaged under the path
`bin/foo_bin`.
```gn
import("//build/package.gni")
executable("bin") {
...
}
package("foo_pkg") {
deps = [ ":bin" ]
binaries = [
{
name = "bin"
dest = "foo_bin"
}
]
meta = [
{
path = "meta/foo_bin.cmx"
dest = "foo.cmx"
}
]
}
```
The new templates allow targets that produce files, such as `executable()`
above, to decide which files they produce and where they're placed. This is
important because some targets produce multiple files, or might produce
different files based on the build configuration (for instance if building
for a different target architecture). In order to control the paths of
packaged files, developers should work with the templates for the targets
that produce those files. For instance:
```gn
import("//build/components.gni")
executable("bin") {
output_name = "foo_bin"
...
}
fuchsia_component("foo_cmp") {
deps = [ ":bin" ]
manifest = "meta/foo_bin.cmx"
}
fuchsia_package("foo_pkg") {
deps = [ ":foo_cmp" ]
}
```
## Shell binaries
The legacy `package()` template allowed developers to make a particular binary
in the package available to `fx shell`.
```gn
import("//build/package.gni")
# `fx shell echo Hello World` prints "Hello World"
executable("bin") {
output_name = "echo"
...
}
package("echo") {
binaries = [
{
name = "echo"
dest = "echo"
shell = true
}
]
deps = [ ":bin" ]
}
```
The new templates support this feature as follows:
```gn
import("//build/components.gni")
# `fx shell echo Hello World` prints "Hello World"
executable("bin") {
output_name = "echo"
...
}
fuchsia_shell_package("echo") {
deps = [ ":bin" ]
}
```
Note that in the `package()` example the binary is explicitly named "echo",
which is the same name that's used for its intrinsic name
(`output_name = "echo"`). The new templates don't have this renaming behavior,
and instead let the target that produces the binary (`executable()` in this
case) decide the file name, as determined by the `output_name` specified (or the
executable target's name if `output_name` isn't specified).
This feature was left out intentionally.
Moving forward the use of legacy shell tools is discouraged.
## Go `grand_unified_binary`
"Grand unified binary" (GUB) is a single binary that merges together multiple Go
programs. The entry point to the combined program can identify which sub-program
the caller intends to run based on the filename of the invocation (`argv[0]`).
Therefore in order to include GUB in your package and invoke a sub-program the
common practice is to rename the binary.
The legacy `package()` template allowed developers to accomplish this as shown
below:
```gn
import("//build/go/go_library.gni")
import("//build/package.gni")
go_library("my_tool") {
...
}
package("tools") {
deps = [
"//src/go/grand_unified_binary",
]
binaries = [
{
name = "my_tool"
source = "grand_unified_binary"
}
]
}
```
The new templates support this feature as follows:
```gn
import("//build/go/go_library.gni")
import("//src/go/grand_unified_binary/gub.gni")
import("//build/components.gni")
go_library("my_tool") {
...
}
grand_unified_binary("bin") {
output_name = "my_tool"
}
fuchsia_package("tools") {
deps = [ ":bin" ]
}
```
## Legacy component index (aka `fx run my_package`)
The legacy `package()` template supported a short-form syntax for launching legacy
v1 components in the legacy sys shell.
```gn
import("//build/package.gni")
executable("bin") {
output_name = "echo"
sources = [ "echo.cc" ]
}
package("echo") {
deps = [ ":bin" ]
binaries = [
{
name = "echo"
},
]
meta = [
{
path = "meta/echo.cmx"
dest = "echo.cmx"
},
]
}
```
```posix-terminal
fx run echo Hello World
```
This is also known as the [Component Index][component-index].
The new templates don't support this feature out of the box, but you can use the
full launch URL.
```posix-terminal
fx run fuchsia-pkg://fuchsia.com/echo#meta/echo.cmx Hello World
```
The plan is to deprecate the legacy shell and the legacy component index along
with it, but there is currently no concrete timeline for this deprecation. If
you'd like to keep the old behavior, you can do so with this special syntax:
```gn
import("//build/components.gni")
import("//src/sys/component_index/component_index.gni")
executable("bin") {
output_name = "echo"
sources = [ "echo.cc" ]
}
add_to_component_index("component_index") {
package_name = "echo"
manifest = "meta/echo.cmx"
}
fuchsia_package_with_single_component("echo") {
deps = [
":bin",
":component_index",
]
manifest = "meta/echo.cmx"
}
```
## Other unsupported features
Note that some features of `package()` are unsupported moving forward. If your
package depends on them then at this time it cannot be migrated to the new
templates. These unsupported features include:
* Marking a test as disabled. Instead, change the test source code to mark it
as disabled, or comment out the disabled test component from the build file.
* `__deprecated_system_image`: the legacy approach to including a package in
the system image is not supported moving forward. A solution is being
prepared and will be available later in 2021.
Nearly all existing uses of this legacy feature are done via the
`driver_package()` wrapper, which currently cannot be migrated.
[build-components]: /docs/development/components/build.md
[component-index]: /src/sys/component_index/component_index.gni
[glossary.component-manifest]: /docs/glossary/README.md#component-manifest
[glossary.component-url]: /docs/glossary/README.md#component-url
[pm]: /src/sys/pkg/bin/pm/README.md
[resource-data]: /docs/development/components/data.md
[restrict-log-severity]: /docs/concepts/testing/logs.md#restricting_log_severity
[test-environments]: /docs/concepts/testing/environments.md
[working-with-packages]: /docs/development/idk/documentation/packages.md