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