blob: c0b6773bb160801256f6ab004fadcd7a8a3d5c0f [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_action.gni")
import("//build/images/args.gni")
import("//build/images/supports_fastboot_fvm.gni")
import("//build/images/vbmeta.gni")
import("//build/info/info.gni")
import("//build/sdk/product_bundle_transfer_manifest.gni")
import("//bundles/assembly/platform_aibs.gni")
import("//sdk/config.gni")
import("//src/sys/pkg/bin/package-tool/package-tool.gni")
# A GN wrapper for a Bazel product bundle target. From GN's perspective, the
# output product bundle is opaque (only a manifest file containing paths to the
# Bazel output base). This template only useful if you have a downstream target
# in GN that is capable of consuming a product bundle built by Bazel in its
# entirety.
#
# Parameters
#
# bazel_product_bundle_target (required)
# The Bazel product bundle target to build.
# Type: label (from BUILD.bazel)
#
# bazel_product_image_target (required)
# The Bazel product image target for this product bundle.
#
# When set, two extra sub_targets are provided to access outputs from Bazel
# product image build steps:
#
# * ${target_name}_product_assembly: for image_assembly.json
# * ${target_name}_create_system: for images.json
#
# NOTE: This template does not check this is the actual product image target
# used in `bazel_product_bundle_target`.
#
# Type: label (from BUIDL.bazel)
#
# bazel_recovery_image_target (optional)
# The Bazel recovery image target for this product bundle.
#
# When set, one extra sub_target is provided to access outputs from Bazel
# recovery image build steps:
#
# * ${target_name}_create_recovery_system: for images.json
#
# NOTE: This template does not check this is the actual recovery image target
# used in `bazel_product_bundle_target`.
#
# Type: label (from BUIDL.bazel)
#
# bazel_inputs_from_gn (required)
# The Bazel input targets (defined by bazel_input_xxx GN templates) used to
# plumb outputs from GN/Ninja to Bazel. This list should include all GN
# targets producing outputs used in the Bazel product bundle. This is usually
# legacy images configurations, legacy AIBs, prebuilt packages from GN, etc.
#
# For example:
#
# * //build/images/fuchsia:fuchsia.bazel_images_config_inputs
# * //build/images/fuchsia:fuchsia.legacy_aib_bazel_inputs
#
# Type: list(label)
#
# allow_eng_platform_bundle_use (optional; default=false)
# If true, allow the 'eng' platform bundles to be used by the assembled
# system. (This is only a check made by GN, assembly itself may still access
# them)
# Type: bool
# Default: false
#
# deps
# metadata
# testonly
# visibility
#
template("bazel_product_bundle") {
assert(defined(invoker.bazel_product_bundle_target),
"bazel_product_bundle_target is required")
assert(defined(invoker.bazel_product_image_target),
"bazel_product_image_target is required")
assert(defined(invoker.bazel_inputs_from_gn),
"bazel_inputs_from_gn is required")
labels = {
bazel_product_bundle = "${target_name}_bazel_action"
transpose_paving_script = "${target_name}_paving_script_transpose"
package_manifest_list = "${target_name}_package_manifests_list"
transfer_manifest = "${target_name}_transfer_manifest"
if (defined(invoker.bazel_product_image_target)) {
bazel_product_assembly = "${target_name}_product_assembly"
bazel_create_system = "${target_name}_create_system"
}
}
files = {
out_dir = target_name
transposed_paving_script = "${out_dir}/pave.sh"
original_paving_script = "${transposed_paving_script}.orig"
product_bundle_out_dir = "${out_dir}/product_bundle"
package_manifests_out_dir = "${out_dir}/manifests"
transfer_manifest_out_dir = "${out_dir}/transfer_manifest"
transfer_json = "${transfer_manifest_out_dir}/transfer.json"
if (defined(invoker.bazel_product_image_target)) {
product_assembly_out_dir = labels.bazel_product_assembly
create_system_out_dir = labels.bazel_create_system
}
}
_aib_bazel_inputs = []
if (defined(invoker.allow_eng_platform_bundle_use) &&
invoker.allow_eng_platform_bundle_use) {
_aibs_to_use = eng_platform_aib_labels
not_needed(invoker, [ "allow_userdebug_platform_bundle_use" ])
} else {
if (defined(invoker.allow_userdebug_platform_bundle_use) &&
invoker.allow_userdebug_platform_bundle_use) {
_aibs_to_use = userdebug_platform_aib_labels
} else {
_aibs_to_use = user_platform_aib_labels
}
}
foreach(_aib, _aibs_to_use) {
_aib_bazel_inputs += [ "${_aib}_bazel_inputs" ]
}
# NOTE: Only depend on product image targets if your outputs are not included
# in product bundles.
_product_assembly_target = "${target_name}_product_assembly"
bazel_action(_product_assembly_target) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
"deps",
])
command = "build"
bazel_targets = [ invoker.bazel_product_image_target + "_product_assembly" ]
bazel_inputs = _aib_bazel_inputs + invoker.bazel_inputs_from_gn
copy_outputs = [
{
bazel = "{{BAZEL_TARGET_OUT_DIR}}/{{BAZEL_TARGET_NAME}}_out/image_assembly.json"
ninja = "${_product_assembly_target}/image_assembly.json"
},
]
}
_create_system_target = "${target_name}_create_system"
bazel_action(_create_system_target) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
"deps",
])
command = "build"
bazel_targets = [ invoker.bazel_product_image_target ]
bazel_inputs = _aib_bazel_inputs + invoker.bazel_inputs_from_gn
allow_directory_in_outputs = true
copy_outputs = [
{
bazel = "{{BAZEL_TARGET_OUT_DIR}}/{{BAZEL_TARGET_NAME}}_out"
ninja = _create_system_target
},
]
directory_timestamp_outputs = [ "${_create_system_target}/images.json" ]
}
if (defined(invoker.bazel_recovery_image_target)) {
_create_recovery_system_target = "${target_name}_create_recovery_system"
bazel_action(_create_recovery_system_target) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
"deps",
])
command = "build"
bazel_targets = [ invoker.bazel_recovery_image_target ]
bazel_inputs = _aib_bazel_inputs + invoker.bazel_inputs_from_gn
allow_directory_in_outputs = true
copy_outputs = [
{
bazel = "{{BAZEL_TARGET_OUT_DIR}}/{{BAZEL_TARGET_NAME}}_out"
ninja = _create_recovery_system_target
},
]
directory_timestamp_outputs =
[ "${_create_recovery_system_target}/images.json" ]
}
}
bazel_action(labels.bazel_product_bundle) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
"deps",
])
no_output_dir_leaks = false
command = "build"
bazel_targets = [ invoker.bazel_product_bundle_target ]
bazel_inputs = _aib_bazel_inputs + invoker.bazel_inputs_from_gn
# Directory outputs are OK because `product_bundle.json` correctly
# represents the freshness of all outputs.
allow_directory_in_outputs = true
copy_outputs = [
{
bazel = "{{BAZEL_TARGET_OUT_DIR}}/{{BAZEL_TARGET_NAME}}_out"
ninja = files.product_bundle_out_dir
},
# The pave.sh script contains sub-paths {{BAZEL_TARGET_NAME}}_out
# that need to be substituted with "product_bundle" to work correctly
# with the Ninja directory, so copy it for later processing.
{
bazel = "{{BAZEL_TARGET_OUT_DIR}}/{{BAZEL_TARGET_NAME}}_pave.sh"
ninja = files.original_paving_script
},
]
directory_timestamp_outputs = [
"${files.product_bundle_out_dir}/product_bundle.json",
"${files.product_bundle_out_dir}/system_a/fuchsia.zbi",
"${files.product_bundle_out_dir}/system_a/fvm.blk",
]
# Populate metadata when Bazel image is not used will pollute GN assembly.
if (use_bazel_images_only) {
_label_dir = get_label_info(":${target_name}", "dir")
_full_label = "${_label_dir}:${target_name}($current_toolchain)"
_system_a_root = rebase_path(target_gen_dir, root_out_dir) +
"/${files.product_bundle_out_dir}/system_a"
# This value can be set (e.g. for testing) with `--args sdk_id=1234` on
# the `fx set` call.
# In the future, the product bundles should be versioned independently of
# the sdk version. So far they have been the same value.
product_version = sdk_id
assert(product_version != "")
# TODO(https://fxbug.dev/127440): Add metadata for recovery image as well.
metadata = {
images = [
{
name = "zircon-a"
type = "zbi"
cpu = current_cpu
label = _full_label
path = "${_system_a_root}/fuchsia.zbi"
archive = true
bootserver_pave = []
if (!sign_zbi) {
bootserver_pave += [ "--zircona" ]
fastboot_flash = []
if (zircon_a_partition != "") {
fastboot_flash += [ zircon_a_partition ]
}
if (zircon_b_partition != "") {
fastboot_flash += [ zircon_b_partition ]
}
}
},
{
name = "blob"
type = "blk"
cpu = current_cpu
label = _full_label
path = "${_system_a_root}/blob.blk"
},
{
name = "storage-full"
cpu = current_cpu
type = "blk"
label = _full_label
path = "${_system_a_root}/fvm.blk"
archive = add_qemu_to_build_archives
},
{
name = "storage-sparse"
cpu = current_cpu
type = "blk"
label = _full_label
path = "${_system_a_root}/fvm.sparse.blk"
archive = true
bootserver_pave = [ "--fvm" ]
},
{
name = "fvm.blob.sparse"
cpu = current_cpu
type = "blk"
label = _full_label
path = "${_system_a_root}/fvm.blob.sparse.blk"
# Hack: Infra expects bootserver_pave to be present
# in the GN graph for this image to be built.
bootserver_pave = []
},
]
if (supports_fastboot_fvm) {
images += [
{
name = "fvm.fastboot"
cpu = current_cpu
type = "blk"
label = _full_label
path = "${_system_a_root}/fvm.fastboot.blk"
archive = true
fastboot_flash = [ fvm_partition ]
},
]
}
if (use_vbmeta) {
images += [
{
name = "zircon-a"
cpu = current_cpu
type = "vbmeta"
label = _full_label
path = "${_system_a_root}/fuchsia.vbmeta"
archive = true
bootserver_pave = [ "--vbmetaa" ]
fastboot_flash = []
if (vbmeta_a_partition != "") {
fastboot_flash += [ vbmeta_a_partition ]
}
if (vbmeta_b_partition != "") {
fastboot_flash += [ vbmeta_b_partition ]
}
},
]
}
product_bundles = [
{
label = get_label_info(":$target_name", "label_with_toolchain")
path =
rebase_path("${target_gen_dir}/${files.product_bundle_out_dir}",
root_build_dir)
name = "${build_info_product}.${build_info_board}"
product_version = product_version
transfer_manifest_path =
rebase_path("${target_gen_dir}/${files.transfer_json}",
root_build_dir)
transfer_manifest_url = "file://" + transfer_manifest_path
},
]
}
}
}
action(labels.transpose_paving_script) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
script = "//build/bazel/assembly/transpose_paving_script.py"
inputs = [ "${target_gen_dir}/${files.original_paving_script}" ]
outputs = [ "${target_gen_dir}/${files.transposed_paving_script}" ]
args = [
"--input",
rebase_path(inputs[0], root_build_dir),
"--output",
rebase_path(outputs[0], root_build_dir),
"--src-dir",
get_label_info(invoker.bazel_product_bundle_target, "name") + "_out",
"--dst-dir",
"product_bundle",
]
deps = [ ":${labels.bazel_product_bundle}" ]
}
package_tool_package_manifest_list_create(labels.package_manifest_list) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
product_bundle = "${target_gen_dir}/${files.product_bundle_out_dir}"
manifests_dir = "${target_out_dir}/${files.package_manifests_out_dir}"
deps = [ ":${labels.bazel_product_bundle}" ]
}
product_bundle_transfer_manifest(labels.transfer_manifest) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
product_bundle_target = ":${labels.bazel_product_bundle}"
product_bundle_dir = "${target_gen_dir}/${files.product_bundle_out_dir}"
output_dir = "${target_gen_dir}/${files.transfer_manifest_out_dir}"
}
# A convenience group for easy `fx build` invocation.
group(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
deps = [
":${labels.bazel_product_bundle}",
":${labels.package_manifest_list}",
":${labels.transfer_manifest}",
":${labels.transpose_paving_script}",
]
}
}