blob: 1fbbb53f64305464e9bcb27fda776acade2408f0 [file] [log] [blame]
# Copyright 2024 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("//build/assembly/product_assembly_config_file_impl.gni")
import("//build/python/python_action.gni")
# Define developer overrides for product assembly
#
# Params (all are optional):
#
# developer_only_options
# [scope] This is a set of flags and settings for product assembly that are
# only available as developer overrides, they are not available to products
# via the 'product_assembly_configuration()' template. It's a scope with
# the following fields (all optional):
#
# all_packages_in_base (optional; default=false)
# [bool] If set to true, all packages are moved from cache to base, and
# all platform-defined universe packages (such as shell commands) are as
# well.
#
# platform
# [scope] This is a set of values to override / overlay onto the platform
# configuration.
#
# kernel
# [scope] This is a set of flags and settings specifically for the kernel.
# It's a scope with the following fields (all optional):
#
# command_line_args (optional; defauilt = [])
# [list, strings] A list of kernel command-line arguments to add to the
# zbi that's created by assembly.
#
# base_packages [optional]
# [list, GN labels] A list of GN labels of fuchsia_package targets to
# include in the base package set.
#
# Note: These are direct labels for specific targets, not deps to walk for
# metadata. If the target isn't a package target, it will cause an error
# like:
# "no dependency provides the input <package_name>/package_manifest.json"
#
# cache_packages [optional]
# [list, GN labels] A list of GN labels of fuchsia_package targets to
# include in the cache package set.
#
# flexible_packages [optional]
# [list, GN labels] A list of GN labels of fuchsia_package targets that
# assembly may choose to put in base, cache, or elsewhere depending on the
# assembly context.
#
# bootfs_packages [optional]
# [list, GN labels] A list of GN labels of fuchsia_package targets to
# include in the bootfs package set.
#
# Note: These are direct labels for specific targets, not deps to walk for
# metadata. If the target isn't a package target, it will cause an error
# like:
# "no dependency provides the input <package_name>/package_manifest.json"
#
# Note: These are direct labels for specific targets, not deps to walk for
# metadata. If the target isn't a bootfs_files_for_assembly target, it will
# cause an error like:
# "no dependency provides the input <package_name>/bootfs_files.json"
#
# shell_commands (optional; default: empty)
# [list of scopes] A list of scopes that describe the shell commands for each
# listed package (the packages need to be separately included in the desired
# package set).
#
# Example:
# shell_commands = [
# {
# "package_name = "//third_party/sbase"
# components = [ "ls" ]
# },
# ]
#
# compiled_packages [optional]
# [list of GN scopes] List of GN scopes of `CompiledPackageDefinition`s
# that describe packages that are to be built dynamically by Assembly, for
# example, the `core` package. This is passed directly through to the AIB
# config so all paths should be rebased by the caller.
#
# Example:
#
# # Add a core shard
# compiled_packages = [
# {
# name = "core"
# components = [
# {
# component_name = "core"
# shards = [
# "//src/sys/process-resolver/meta/process_resolver.core_shard.cml",
# ]
# },
# ...
# ],
# contents = [ {
# label = "//some/gn/label"
# source = "//som/gn/file/path"
# destination = "foo/bar"
# } ]
# },
# ]
#
# shards [optional]
# [list of GN file paths] List of CML files to merge together when
# compiling the component.
#
# contents [optional]
# [list of GN scopes] List of GN scopes that describe a source/destination
# pair for a file to include in the package when it's compiled. An
# optional 'label' field is required when the file is created by the
# build, and is the label of the target that creates the file.
#
template("assembly_developer_overrides") {
labels = {
# So it can be reused.
target_name = target_name
assembly_overrides_intermediate =
"${target_name}.product_assembly_overrides.intermediate.json"
# This is a second target created by the product_assembly_config_file()
# template that wraps up all the input file labels found in the product and
# platform config with the deps that are passed to this template.
assembly_overrides_intermediate_inputs =
"${assembly_overrides_intermediate}.inputs"
}
files = {
outdir = "$target_out_dir/$target_name"
assembly_config_file = "$outdir/product_assembly_overrides.json"
assembly_config_file_intermediate =
"$outdir/product_assembly_overrides.intermediate.json"
}
creation_inputs = []
creation_deps = []
# Gather up all the developer-specified packages
_packages = []
foreach(package_set,
[
"base",
"cache",
"flexible",
"bootfs",
]) {
package_set_varname = "${package_set}_packages"
if (defined(invoker[package_set_varname])) {
foreach(package_target, invoker[package_set_varname]) {
_package_out_dir = get_label_info(package_target, "target_out_dir")
_package_name = get_label_info(package_target, "name")
_manifest_path =
"${_package_out_dir}/${_package_name}/package_manifest.json"
_packages += [
{
package = rebase_path(_manifest_path, root_build_dir)
set = package_set
},
]
creation_inputs += [ _manifest_path ]
creation_deps += [ package_target ]
}
}
}
_compiled_packages = []
if (defined(invoker.compiled_packages)) {
foreach(package, invoker.compiled_packages) {
_package = {
}
_package = {
forward_variables_from(package,
"*",
[
"contents",
"components",
"component_includes",
])
}
# Rebase and gather inputs for the contents and component shards
# Gather the deps and inputs files for the package contents.
if (defined(package.contents)) {
_contents = []
foreach(entry, package.contents) {
creation_inputs += [ entry.source ]
creation_deps += [ entry.label ]
_contents += [
{
destination = entry.destination
source = rebase_path("${entry.source}", root_build_dir)
},
]
}
_package.contents = _contents
}
# Gather the core shards as input files
if (defined(package.components)) {
_components = []
foreach(entry, package.components) {
creation_inputs += entry.shards
_components += [
{
forward_variables_from(entry, "*", [ "shards" ])
shards = rebase_path(entry.shards, root_build_dir)
},
]
}
_package.components = _components
}
_compiled_packages += [ _package ]
}
}
_shell_commands = []
if (defined(invoker.shell_commands)) {
foreach(shell_command, invoker.shell_commands) {
assert(
defined(shell_command.package),
"shell_command entries must specify a package name: ${shell_command}")
assert(
defined(shell_command.components),
"shell_command components must be a list of strings pointing to binaries that are components in the package that make up the package: ${shell_command}")
_package_name = get_label_info(shell_command.package, "name")
_shell_commands += [
{
package = _package_name
components = shell_command.components
},
]
}
}
_assembly_overrides = {
target_name = get_label_info(":$target_name", "label_no_toolchain")
forward_variables_from(invoker,
[
"developer_only_options",
"platform",
"kernel",
])
packages = _packages
packages_to_compile = _compiled_packages
shell_commands = _shell_commands
}
# Generate the overrides configuration file itself.
#
# This uses the product_assembly_config_file() template to properly convert
# any file paths in the 'platform' and 'product' sections that need to be
# converted from GN paths into rebased file paths. See the template's file
# for more information on those paths.
#
product_assembly_config_file(labels.assembly_overrides_intermediate) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"testonly",
])
visibility = [ ":${labels.target_name}" ]
outputs = [ files.assembly_config_file_intermediate ]
product_assembly_config = _assembly_overrides
}
python_action(labels.target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
binary_label = "//build/assembly/scripts:developer_overrides"
public_deps = [
":${labels.assembly_overrides_intermediate_inputs}",
":${labels.assembly_overrides_intermediate}",
]
inputs = creation_inputs + [ files.assembly_config_file_intermediate ]
deps = creation_deps
outputs = [ files.assembly_config_file ]
args = [
"--input",
rebase_path(files.assembly_config_file_intermediate, root_build_dir),
"--output",
rebase_path(files.assembly_config_file, root_build_dir),
]
# Block all metadata walks for packages, distribution entries, etc. These
# inputs should not exist in metadata walks, as they are added via the paths
# in the assembly config itself.
metadata = {
package_barrier = []
assembly_package_barrier = []
config_package_barrier = []
driver_package_barrier = []
system_image_package_barrier = []
distribution_entries_barrier = []
}
}
}
declare_args() {
# This GN arg enables developer overrides for the given assembly targets
#
# This is a list of scopes that take two fields:
# - assembly: (GN label pattern) the GN label(s) to apply the overrides to
# - overrides (GN label) the label of a set of developer overrides
#
# Example:
#
# product_assembly_overrides = [
# {
# assembly = "//build/images/fuchsia/*"
# overrides = "//local:my_assembly_overrides"
# }
# ]
product_assembly_overrides = []
}
foreach(overrides_def, product_assembly_overrides) {
assert(
defined(overrides_def.assembly),
"'product_assembly_overrides' must specify an assembly target to override using 'assembly'")
assert(
defined(overrides_def.overrides),
"'product_assembly_overrides' must specify an overrides target using 'overrides'")
}