| # 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}" ] |
| } |
| } |