blob: 8318e3b703645843fa1a28956d545f706ed00dd6 [file] [log] [blame]
# Copyright 2020 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.
# Declare data files to be accessible at runtime on the target device.
#
# A resource() target looks just like a copy() target but $outputs are
# relative target paths. Using $data_deps to this resource() target in
# each target whose code uses $outputs at runtime ensures that the files
# will be present on the system.
#
# If the file is not in the source tree, it should be generated by another
# target in the build listed in $deps. If that would be a generated_file()
# target, then use generated_resource() instead of resource().
#
# Using resource() to install an ELF binary file into bin/ or test/ will
# break instrumented builds (with an error that only occurs very late in
# the build, during the packaging step). To solve this, use renamed_binary()
# to install them instead.
#
# Due to this, using resource() with an output directory of bin/ or test/
# is an error by default, but can be overridden for data files by setting
# allow_binary_output_dir to true!
#
# Parameters
#
# data_deps
# Optional: Additional dependencies for the runtime image. These are
# included in the image if this target is, but are not related to the
# $sources list.
# Type: list(label)
#
# deps
# Optional: Targets that produce $sources. Any files listed in
# $sources that are produced by the build should be produced by a
# target listed here. This is the only thing that guarantees those
# files will have been built by the time the image is being packed.
# Targets reached only via this $deps list will *not* contribute their
# own contents to the image directly. For that, list them in $data_deps.
# Targets listed here are used only to produce the $sources files.
# Type: list(label)
#
# outputs
# Required: List of one runtime path. This must be a relative path (no
# leading `/`). It can use placeholders based on $sources; see copy()
# and `gn help source_expansion`. When this resource() target is in
# the dependency graph of a zbi() target, then this is the path within
# the BOOTFS, which appears at /boot in the namespace of early-boot and
# standalone Zircon processes.
# Type: list(path)
#
# sources
# Required: List of files in the source tree or build that become $outputs.
# See copy() for details.
# Type: list(file)
#
# allow_binary_output_dir
# Optional: Set to true to allow copying a resource into either
# bin/ or test/. Useful when installing non-ELF files there, while
# ELF files should be installed using renamed_binary() instead.
# Type: boolean
#
# See copy() for other parameters.
template("resource") {
if (invoker.sources != []) {
_label = get_label_info(":$target_name", "label_with_toolchain")
}
# Prevent binaries to be copied to bin/ or test/ with resource() to prevent
# build breaks with instrumented builds. See https://fxbug.dev/89436
#
_allow_binary_output_dir = defined(invoker.allow_binary_output_dir) &&
invoker.allow_binary_output_dir
if (!_allow_binary_output_dir) {
_outputs = invoker.outputs
# invoker.outputs can be a list or a string. If it is a string, turn
# it into a list here.
if ("${_outputs}" == _outputs) {
_outputs = [ _outputs ]
} else {
assert(_outputs == [ _outputs[0] ],
"outputs should be a string or a list of one string!")
}
_output_dir = get_path_info(_outputs[0], "dir")
assert(
_output_dir != "bin" && _output_dir != "test",
"Installing file to bin/ or test/ requires renamed_binary() or allow_binary_output_dir!")
}
group(target_name) {
forward_variables_from(invoker,
"*",
[
"metadata",
"outputs",
"sources",
])
metadata = {
# Used by the distribution_manifest() template.
distribution_entries_barrier = []
distribution_entries = []
# Used by the zbi() template.
zbi_input_barrier = []
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
# Stop *_manifest() and zbi_test() from picking up files or
# zbi_input() items from the deps, but let them reach the data_deps.
if (defined(data_deps)) {
distribution_entries_barrier += data_deps
zbi_input_barrier += data_deps
}
foreach(source, invoker.sources) {
foreach(target, process_file_template([ source ], invoker.outputs)) {
assert(rebase_path(target, "foo") != target,
"`outputs` in resource() cannot start with /")
distribution_entries += [
{
source = rebase_path(source, root_build_dir)
destination = target
label = _label
},
]
}
}
}
}
}
# Declare data files to be accessible at runtime on the target device.
#
# Similar to resource() but with a different interface that allows grouping
# multiple files into a single target when their packaged paths don't follow
# a common pattern.
#
# Parameters
#
# data_deps
# Optional: Additional dependencies for the runtime image. These are
# included in the image if this target is, but are not related to the
# $sources list.
# Type: list(label)
#
# deps
# Optional: Targets that produce $sources. Any files listed in
# $sources that are produced by the build should be produced by a
# target listed here. This is the only thing that guarantees those
# files will have been built by the time the image is being packed.
# Targets reached only via this $deps list will *not* contribute their
# own contents to the image directly. For that, list them in $data_deps.
# Targets listed here are used only to produce the $sources files.
# Type: list(label)
#
# files
# Required: List of scopes containing `source` and `dest` paths.
# `source` paths are local file paths.
# `dest` paths are packaged paths.
# For instance:
# files = [
# {
# source = "//path/to/file.txt"
# dest = "data/first.txt"
# },
# {
# source = "//path/to/other_file.txt",
# dest = "data/second.txt"
# },
# ]
# Type: list(scope)
#
# allow_binary_output_dir
# See resource()
#
# testonly, visibility
template("resource_group") {
if (invoker.files != []) {
_label = get_label_info(":$target_name", "label_with_toolchain")
}
if (!(defined(invoker.allow_binary_output_dir) &&
invoker.allow_binary_output_dir)) {
# Prevent binaries to be copied to bin/ or test/ with resource() to prevent
# build breaks with instrumented builds. See https://fxbug.dev/89436
#
# NOTE: This check cannot be performed in the metadata definition below
# because GN will complain that the _dest_with_prefix temporary variable
# is not a list (metadata scope variables can only be lists).
foreach(file, invoker.files) {
_dest_dir = get_path_info(file.dest, "dir")
assert(
_dest_dir != "bin" && _dest_dir != "test",
"Installing file to bin/ or test/ requires renamed_binary() or allow_binary_output_dir!")
}
}
group(target_name) {
forward_variables_from(invoker,
[
"deps",
"testonly",
"visibility",
])
metadata = {
# Used by the distribution_manifest() template.
distribution_entries_barrier = []
distribution_entries = []
# Used by the zbi() template.
zbi_input_barrier = []
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
# Stop *_manifest() and zbi_test() from picking up files or
# zbi_input() items from the deps, but let them reach the data_deps.
if (defined(data_deps)) {
distribution_entries_barrier += data_deps
zbi_input_barrier += data_deps
}
foreach(file, invoker.files) {
distribution_entries += [
{
source = rebase_path(file.source, root_build_dir)
destination = file.dest
label = _label
},
]
}
}
}
}
# resource_tree() is similar to resource() but makes it easy to replicate
# a tree of sources files, relative to a given sources path prefix, to a
# given destination directory.
#
# For example:
#
# //some/dir/BUILD.gn:
# resource_trees("my-resources") {
# sources_root = "res"
# sources = [
# foo.resource",
# bar/bar-1.resource",
# ]
# dest_dir = "data/resources"
# }
#
# Will declare the following installation requirements:
#
# //some/dir/res/foo.resource --> data/resources/foo.resource
# //some/dir/res/bar/bar.resource --> data/resources/bar/bar.resource
#
# This is difficult to do with resource() because GN source expansion
# cannot preserve the original sources input paths.
#
# This template is useful to avoid calling resource() multiple times
# in a loop when dealing with resource files laid out into different
# sub-directories. Note that the files cannot be renamed though!
#
# Parameters
#
# source_root
# Optional: A path prefix that is prepended to all items in the 'sources'
# list. If not specified, the current target's directory is used.
# Type: string(path)
#
# sources
# Required: List of files in the source tree or build that will be
# installed. Each 'file' item in this list is installed to
# '$dest_dir/$file', and its content taken from '$sources_root/$file'.
# Note that unlike resource(), there is no way to transform or expand
# source paths.
# Type: list(file)
#
# dest_dir
# Required: Destination path where all sources are installed.
# Cannot start with a "/". Use an empty string to install files directory
# to the package's top-level directory.
# Type: string(path)
#
# data_deps
# Optional: Additional dependencies for the runtime image. These are
# included in the image if this target is, but are not related to the
# $sources list.
# Type: list(label)
#
# allow_binary_output_dir
# See resource()
#
# deps
# Optional: Targets that produce $sources. Any files listed in
# $sources that are produced by the build should be produced by a
# target listed here. This is the only thing that guarantees those
# files will have been built by the time the image is being packed.
# Targets reached only via this $deps list will *not* contribute their
# own contents to the image directly. For that, list them in $data_deps.
# Targets listed here are used only to produce the $sources files.
# Type: list(label)
#
template("resource_tree") {
assert(defined(invoker.sources), "sources is required!")
assert(defined(invoker.dest_dir), "dest_dir is required!")
dest_dir = invoker.dest_dir
if (dest_dir != "") {
# Sanitize dest_dir and append a directory separator.
assert(rebase_path(dest_dir, "foo") != dest_dir,
"dest_dir cannot start with /: $dest_dir")
assert(dest_dir != "." && dest_dir != ".." &&
string_replace(dest_dir, "./", "") == dest_dir,
"dest_dir cannot contain . or .. path elements!: $dest_dir")
if (!(defined(invoker.allow_binary_output_dir) &&
invoker.allow_binary_output_dir)) {
assert(
dest_dir != "bin" && dest_dir != "test",
"Installing file to bin/ or test/ requires renamed_binary() or allow_binary_output_dir!")
}
dest_dir = string_replace(dest_dir + "/", "//", "/")
}
if (defined(invoker.sources_root)) {
assert(invoker.sources_root != "", "sources_root cannot be empty!")
sources_prefix = invoker.sources_root
# Append trailing separator if needed
if (string_replace(sources_prefix + "###", "/###", "") ==
sources_prefix + "###") {
sources_prefix += "/"
}
} else {
sources_prefix = ""
}
target_label = get_label_info(":$target_name", "label_with_toolchain")
if (invoker.sources == []) {
# Support resource_tree() targets with empty sources list.
not_needed(invoker,
[
"dest_dir",
"sources_root",
])
not_needed([
"sources_prefix",
"dest_dir",
"target_label",
])
}
group(target_name) {
forward_variables_from(invoker,
"*",
[
"dest_dir",
"metadata",
"sources",
"sources_root",
])
metadata = {
# Used by the distribution_manifest() template.
distribution_entries_barrier = []
distribution_entries = []
# Used by the zbi() template.
zbi_input_barrier = []
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
# Stop *_manifest() and zbi_test() from picking up files or
# zbi_input() items from the deps, but let them reach the data_deps.
if (defined(data_deps)) {
distribution_entries_barrier += data_deps
zbi_input_barrier += data_deps
}
foreach(_source, invoker.sources) {
distribution_entries += [
{
source = rebase_path(sources_prefix + _source, root_build_dir)
destination = dest_dir + _source
label = target_label
},
]
}
}
}
}