blob: 059eb6860b3642273d933061a7087cf148e55f19 [file] [log] [blame]
# Copyright 2023 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/bazel/bazel_inputs.gni")
import("//build/group_with_inputs.gni")
import("//build/python/python_action.gni")
# Creates the assembly Board configuration file, and it's main Hardware Support
# Bundle, which respectively provide information about the board and components
# and drivers which are to be included by assembly when assembling a product for
# this board.
#
# NOTE: This template DOES NOT use GN metadata, all labels for packages must be
# the actual target that creates the package.
#
# Parameters
#
# Board
#
# name (optional)
# [string] The name of the board, defaults to '$target_name'
#
# hardware_info (optional)
# [scope] Data provided via the 'fuchsia.hwinfo.Board' protocol. Fields:
# - name [string] - The board name to provide via hwinfo, if different from
# the name in build info (provided above). Must be 32
# bytes or less.
# - vendor_id [u32] - Must be provided with 'product_id'. Used to add a
# platform_id item to the ZBI.
# - product_id [u32] - Must be provided with 'vendor_id'. Used to add a
# platform_id item to the ZBI.
# - revision [u32] - Must be provided with 'product_id' and 'vendor_id'.
# Used to add a board_info item to the ZBI.
#
# provided_features (optional)
# [list, strings] A list of strings which are named features, capabilities,
# or requirements that are used by assembly to include optional portions of
# the platform, or to indicate that the board provides (or its drivers
# provide).
#
# Examples:
# - `fuchsia::network_require_netstack3` - netstack3 (implemented in Rust)
# must be used on this board, and not netstack2 (implemented in Go).
#
# - `fuchsia::wlan_softmac` - used to tell assembly that this board uses a
# "soft MAC" wifi driver.
#
# - `fuchsia::wlan_fullmac` - used to tell assembly that this board uses a
# wifi driver that implements the full MAC itself.
#
# The list if valid strings is currently an unstable API between boards and
# assembly and can change at any time.
#
# input_bundles (optional)
# [list; GN Labels] The GN labels of the Board Input Bundles for this board.
# Each must be the label of a board_input_bundle() target. If the target
# isn't a board_input_bundle() target, it will cause an error such as:
# "no dependency provides the input <target_name>/board_input_bundle.json"
#
# filesystems (optional)
# [scope] A GN scope that describes configuration to use for various
# different filesystems in order to use them with this board. This doesn't
# trigger the creation of these filesystems, but rather is board-specific
# information that's needed to correctly create those filesystems when they
# are requested by the product.
#
# NOTE: This template converts GN paths for vbmeta keys into the correctly
# rebased form automatically.
#
# devicetree (optional)
# [GN Label] The GN label of the devicetree binary for this board. This
# should be a devicetree() target.
#
# Outputs
# A directory structure and manifest
#
# manifest path:
# $target_out_dir/$target_name/board_configuration.json
#
# or if the defaults are overridden:
# $bundle_dir/$name/board_configuration.json
#
# GN usual meanings
# testonly, visibility
#
template("board_configuration") {
bundles_dir = target_out_dir
board_name = target_name
if (defined(invoker.name)) {
board_name = invoker.name
}
labels = {
main_target = target_name
# Outputs
bazel_inputs = "${target_name}.bazel_input"
assembly_inputs = "${target_name}.assembly_inputs"
# Inputs
if (defined(invoker.input_bundles)) {
input_bundles = invoker.input_bundles
# The validation task that the bundles are all created by the
# board_input_bundle() template.
validate_input_bundles = "${main_target}.validate_input_bundle_targets"
}
# The input bundle copying targets.
input_bundle_copy_targets = []
# Intermediate Files
base_info = "${target_name}.base_info"
}
files = {
# Outputs
# The directory where the board configuration file is written to. This is
# named for the target, not the name of the board, if the name is being
# overridden.
#
# This allows other templates to compute the path to the main configuration
# file based on just the label.
board_configuration_dir = "${bundles_dir}/${target_name}"
# The "official" output board configuration file
board_configuration = "${board_configuration_dir}/board_configuration.json"
# The board input bundles that are needed for OOT use.
assembly_inputs = "${bundles_dir}/${target_name}.assembly_inputs.json"
# The files that we create as book-keeping between our tasks.
depfile = "${bundles_dir}/${target_name}.d"
# Intermediate Files
_gen_files = "${target_gen_dir}/${target_name}"
base_info = "${_gen_files}.base_info.json"
if (defined(labels.input_bundles)) {
# The directory of input bundles
input_bundles_dir = "${board_configuration_dir}/input_bundles"
input_bundle_dirs = []
}
}
creation_deps = []
# Check the 'filesystems' parameter for any vbmeta keys. If found, add them
# as 'inputs' to a group_with_inputs() for vbmeta, and rebase them from GN
# file-paths to the appropriate form that will be needed by assembly.
if (defined(invoker.filesystems)) {
_filesystems = invoker.filesystems
if (defined(_filesystems.vbmeta)) {
_vbmeta = _filesystems.vbmeta
_vbmeta_rebased = {
forward_variables_from(_filesystems.vbmeta,
"*",
[
"key",
"key_metadata",
])
}
if (defined(_vbmeta.key)) {
_vbmeta_key_filename = get_path_info(_vbmeta.key, "file")
_vbmeta_rebased.key = "vbmeta/${_vbmeta_key_filename}"
copy("${target_name}.vbmeta.key") {
visibility = [ ":${labels.main_target}" ]
sources = [ _vbmeta.key ]
outputs =
[ "${files.board_configuration_dir}/${_vbmeta_rebased.key}" ]
# keys currently need to be source files.
deps = []
}
creation_deps += [ ":${target_name}.vbmeta.key" ]
}
if (defined(_vbmeta.key_metadata)) {
_vbmeta_key_metadata_filename =
get_path_info(_vbmeta.key_metadata, "file")
_vbmeta_rebased.key_metadata = "vbmeta/${_vbmeta_key_metadata_filename}"
copy("${target_name}.vbmeta.key_metadata") {
visibility = [ ":${labels.main_target}" ]
sources = [ _vbmeta.key_metadata ]
outputs = [
"${files.board_configuration_dir}/${_vbmeta_rebased.key_metadata}",
]
# keys currently need to be source files.
deps = []
}
creation_deps += [ ":${target_name}.vbmeta.key_metadata" ]
}
if (_vbmeta_rebased != {
}) {
# replace the vbmeta field of _filesystems with one that contains the
# rebased file.
_filesystems.vbmeta = {
}
_filesystems.vbmeta = _vbmeta_rebased
}
}
}
if (defined(labels.input_bundles)) {
_input_bundle_manifest_files = []
foreach(input_bundle, labels.input_bundles) {
_input_bundle_name = get_label_info(input_bundle, "name")
_input_bundle_input_dir = get_label_info(input_bundle, "target_out_dir") +
"/" + _input_bundle_name
_input_bundle_input_file =
"${_input_bundle_input_dir}/board_input_bundle.json"
_input_bundle_manifest_files += [ _input_bundle_input_file ]
_input_bundle_output_dir =
"${files.input_bundles_dir}/${_input_bundle_name}"
_input_bundle_output_file =
"${_input_bundle_output_dir}/board_input_bundle.json"
assert(
files.input_bundle_dirs ==
files.input_bundle_dirs + [ _input_bundle_output_dir ] -
[ _input_bundle_output_dir ],
"All input bundle targets must have unique 'name' portions of their label.")
files.input_bundle_dirs += [ _input_bundle_output_dir ]
# Copy the Board Input Bundle into the board's own directory, to make the
# whole board portable.
_input_bundle_copy_target = "${target_name}.${_input_bundle_name}.copy"
action(_input_bundle_copy_target) {
forward_variables_from(invoker, [ "testonly" ])
visibility = [
":${labels.assembly_inputs}",
":${labels.main_target}",
]
script = "//build/copy_tree.py"
deps = [ ":${labels.validate_input_bundles}" ]
depfile = "${target_out_dir}/${target_name}.d"
outputs = [ _input_bundle_output_file ]
# The contents of these folders are dynamic, and managed entirely by this
# action. Further, this action will need to delete items from these
# directories that are not added back (on an incremental build, if an item
# is removed from one of these sets)
hermetic_action_ignored_prefixes = [ _input_bundle_output_dir ]
args = [
rebase_path(_input_bundle_input_dir, root_build_dir),
rebase_path(_input_bundle_output_dir, root_build_dir),
rebase_path(outputs[0], root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
]
}
labels.input_bundle_copy_targets += [ ":${_input_bundle_copy_target}" ]
}
# Validate that the input bundle targets are actually board_input_bundle()
# targets.
group_with_inputs(labels.validate_input_bundles) {
forward_variables_from(invoker, [ "testonly" ])
visibility = labels.input_bundle_copy_targets
deps = labels.input_bundles
inputs = _input_bundle_manifest_files
}
creation_deps += labels.input_bundle_copy_targets
}
if (defined(invoker.devicetree)) {
_dtb_file = get_label_info(invoker.devicetree, "target_out_dir") + "/" +
get_label_info(invoker.devicetree, "name") + ".dtb"
creation_deps += [ invoker.devicetree ]
}
base_info_contents = {
name = board_name
if (defined(invoker.hardware_info)) {
hardware_info = invoker.hardware_info
if (defined(hardware_info.vendor_id) ||
defined(hardware_info.product_id) ||
defined(hardware_info.revision)) {
assert(
defined(hardware_info.vendor_id) &&
defined(hardware_info.product_id) &&
defined(hardware_info.revision),
"If any of 'vendor_id', 'product_id' or 'revision' are set, then all are required")
}
}
if (defined(_filesystems)) {
filesystems = _filesystems
}
if (defined(files.input_bundle_dirs)) {
input_bundles =
rebase_path(files.input_bundle_dirs, files.board_configuration_dir)
}
if (defined(invoker.devicetree)) {
devicetree = rebase_path(_dtb_file, files.board_configuration_dir)
}
forward_variables_from(invoker,
[
"provided_features",
"kernel",
"platform",
])
}
generated_file(labels.base_info) {
forward_variables_from(invoker, [ "testonly" ])
visibility = [ ":${labels.main_target}" ]
outputs = [ files.board_configuration ]
output_conversion = "json"
contents = base_info_contents
}
group(labels.main_target) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
public_deps = [ ":${labels.base_info}" ]
deps = creation_deps
metadata = {
board_configs = [
{
label =
get_label_info(":${labels.main_target}", "label_with_toolchain")
outdir = rebase_path(files.board_configuration_dir, root_build_dir)
},
]
}
}
# Make board configuration and hardware support bundle available to Bazel
bazel_input_resource_directory(labels.bazel_inputs) {
forward_variables_from(invoker, [ "testonly" ])
source_dir = files.board_configuration_dir
dest_dir = rebase_path(files.board_configuration_dir, root_out_dir)
deps = [ ":${labels.main_target}" ]
gn_targets_name = labels.main_target
}
}