# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("cmc.gni")
declare_args() {
# Enable code coverage for Fuchsia components.
fuchsia_code_coverage = false
}
# Defines a Fuchsia component's manifest.
# See: https://fuchsia.dev/fuchsia-src/development/components/build
#
# Parameters
#
# manifest [required]
# The component manifest.
# Type: path
#
# component_name [optional]
# The name of the component.
# Type: string
# Default: target_name
#
# check_includes [optional]
# Check against expect_includes() in deps.
# Warning: Do not disable this unless there is a good, documented reason.
# Type: boolean
# Default: true
#
# restricted_features [optional]
# The set of restricted features to allow.
# The set of features is allowlisted here: //tools/cmc/build/restricted_features/BUILD.gn
# where each feature name is represented by a group of the same name.
# Type: list of strings
# Default: []
#
# experimental_force_runner [optional]
# Set the --experimental-force-runner flag to the given value.
# This flag is experimental and may be removed without warning.
# Type: string
#
# required_offers (optional)
# [list of strings] The set of protocols that should be offered to every child.
#
# required_uses (optional)
# [list of strings] The set of protocols that each child must use.
#
# include_coverage_shard (optional)
# Whether to include the `coverage.shard.cml` in a merged manifest.
# Overrides the default based on `fuchsia_code_coverage`.
# Should only be used in rare exceptions that do not use CML-based routing.
#
# data_deps
# deps
# testonly
# visibility
template("fuchsia_component_manifest") {
assert(
defined(invoker.manifest),
"A `manifest` argument was missing when calling fuchsia_component_manifest($target_name)")
forward_variables_from(invoker, [ "manifest" ])
if (defined(invoker.include_coverage_shard)) {
include_coverage_shard = invoker.include_coverage_shard
} else {
include_coverage_shard = fuchsia_code_coverage
}
if (include_coverage_shard) {
merged_manifest = "${target_name}-coverage"
manifest_file = get_path_info(manifest, "file")
# Put the coverage merged manifest in a coverage directory to avoid
# collision with no base manifest.
manifest_rel_path = "coverage/${manifest_file}"
cmc_merge(merged_manifest) {
forward_variables_from(invoker,
[
"deps",
"testonly",
])
sources = [
"${fuchsia_sdk}/pkg/sys/testing/coverage.shard.cml",
manifest,
]
output_name = manifest_rel_path
}
manifest = "${target_out_dir}/${manifest_rel_path}"
}
_manifest_name = get_path_info(manifest, "name")
cmc_compile(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
"required_offers",
"required_uses",
])
manifest = rebase_path(manifest)
# NOTE: must be kept in sync with path in structured_config.gni
config_values_package_path = "$_manifest_name.cvf"
deps = []
if (defined(invoker.deps)) {
deps += invoker.deps
}
if (include_coverage_shard) {
deps += [ ":${merged_manifest}" ]
}
}
}
# Defines a Fuchsia component.
# See: https://fuchsia.dev/fuchsia-src/glossary#component
#
# A component is defined by a component manifest.
# A component is a unit of executable software on Fuchsia. When the componet is executed, there are usually many files
# needed at runtime, such as the executable itself, shared libraries, and possibly other data resources. These files are
# specified by using the GN concept of "data_deps".
#
# Components are distributed using a fuchsia package which can contain multiple components. The component manifest and
# the runtime dependencies of the component are packaged using the fuchsia_package rule.
#
# By default, the runtime depenencies of the component are included in the package using relative paths calcualted from
# the "closest" root of: $root_gen_dir, $root_dir, $out_dir. If a specific path is desired in the package, the "resources" parameter can
# be used to explicitly specify the path of a specific file.
#
# A component is launched by a URL which identifies the package and the component manifest.
# See: https://fuchsia.dev/fuchsia-src/glossary#component_url
#
# Example
#
# ```
# fuchsia_component("my_component") {
# manifest = "meta/component-manifest.cml"
# resources = [
# {
# path = "testdata/use_case1.json"
# dest = "data/testdata/use_case1.json"
# },
# ]
# data_deps = [ ":hello_world_executable"]
# }
# ```
#
# Parameters
#
# data_deps
# The labels of targets that generate the files needed at runtime by the component.
# At minimum, this should include the label of the binary to include in the component.
#
# Type: list of labels
#
# manifest [optional]
# The source manifest file for this component.
#
# Type: string (filepath)
#
# manifest_output_name [optional]
# The name of the manifest file contained in the distribution that this
# component is included in. The output name should have no extension or
# prefixes. The resulting filename will have the ".cm" extension.
# For example, if `manifest` is "foo.cml" and `manifest_output_name` is "bar",
# the filename will be "bar.cm".
#
# Type: string
# Default: The base file name of `manifest` without an extension.
#
# resources [optional]
# Lists additional files to include for runtime access by the component.
# Defines the resources in a package containing this component. A resource
# is a data file that may be produced by the build system, checked in to a
# source repository, or produced by another system that runs before the
# build. Resources are placed in the `data/` directory of the assembled
# package.
#
# Type: list of scopes. Entries in a scope in the resources list:
# path (required)
# Location of resource in source or build directory. If the
# resource is checked in, this will typically be specified
# as a path relative to the BUILD.gn file containing the
# `package()` target. If the resource is generated, this will
# typically be specified relative to `$target_gen_dir`.
#
# dest (required) string (path) Location the resource will be placed within `data/`.
#
# cm_label [optional]
# Use label of a fuchsia_component_manifest target instead of supplying the manifest source.
# Type: string, GN label e.g. `:my-manifest`
#
# manifest_deps [optional]
# Dependencies for the component's manifest, in case it is generated by another target.
# Type: list of targets
#
# required_offers (optional)
# [list of strings] The set of protocols that should be offered to every child.
#
# required_uses (optional)
# [list of strings] The set of protocols that each child must use.
#
# Standard parameters:
# data_deps
# deps
# testonly
# visibility
#
# Metadata
# contents - list of scopes describing files for this component. This metadata is consumed by
# The fuchsia_package rule, which describes the entries used.
# Entries in scope:
# type: the usage type of the element, manifest or resource.
# Each type can have specific properties included in the scope.
# source [type == manifest || resource] The compiled manifest file to include in
# the package for this component.
# output_name [type == manifest] The basename of the manifest as it should appear in the package.
# manifest_version [type == manifest]
# dest: [type == resource] The package relative path of the resource.
template("fuchsia_component") {
forward_variables_from(invoker, [ "manifest_output_name" ])
_manifest_defined = defined(invoker.manifest)
_cm_label_defined = defined(invoker.cm_label)
assert(
(_manifest_defined && !_cm_label_defined) ||
(!_manifest_defined && _cm_label_defined),
"Exactly one of `manifest` or `cm_label` argument must be specified when calling fuchsia_component($target_name)")
if (defined(invoker.manifest)) {
# Compile the manifest from source
cm_target = "${target_name}_manifest_compile"
fuchsia_component_manifest(cm_target) {
forward_variables_from(invoker,
[
"deps",
"manifest",
"testonly",
"visibility",
"required_offers",
"required_uses",
"include_coverage_shard",
])
if (defined(invoker.manifest_deps)) {
if (!defined(deps)) {
deps = []
}
deps += invoker.manifest_deps
}
}
cm_label = ":${cm_target}"
} else {
cm_label = invoker.cm_label
}
_compiled_manifest_outputs = get_target_outputs(cm_label)
_manifest_source = _compiled_manifest_outputs[0]
group(target_name) {
forward_variables_from(invoker,
[
"data",
"deps",
"data_deps",
"resources",
"resources_in_json_files",
"testonly",
"visibility",
])
# Data is used for adding files as runtime dependencies. Files used as
# sources in the resources parameter are added as data to make sure
# non-generated files listed are captured as dependencies.
if (!defined(data)) {
data = []
}
if (!defined(resources)) {
resources = []
}
if (!defined(deps)) {
deps = []
}
deps += [ cm_label ]
# Create the component metadata entries. These capture the manifest information and
# the resources parameter contents. The metadata is intended for the fuchsia_package rule.
component_contents = [
{
type = "manifest"
source = rebase_path(_manifest_source)
if (defined(manifest_output_name)) {
output_name = manifest_output_name
}
},
]
foreach(resource, resources) {
data += [ resource.path ]
component_contents += [
{
type = "resource"
source = rebase_path(resource.path)
dest = resource.dest
},
]
}
# TODO(richkadel): Changed from the Fuchsia GN SDK to add
# `resources_in_json_files, so additional resources could be computed at
# compile time (in this case, compiled Dart libraries).
if (!defined(resources_in_json_files)) {
resources_in_json_files = []
}
foreach(file, resources_in_json_files) {
data += [ file ]
component_contents += [
{
type = "json_of_resources"
source = file
},
]
}
# The contents of the component are enumerated in the
# metadata.
metadata = {
contents = [ component_contents ]
}
}
}