blob: c0f92ac00e8a0ed9d1345c251c8589fd476f76eb [file]
# 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/config/compiler.gni")
import("//build/python/python_action.gni")
import("//build/sdk/idk_subbuilds.gni")
import("//build/toolchain/rbe.gni")
import("//sdk/config.gni")
# Generate an IDK directory, which combines outputs from different arch- and API
# level-specific sub-builds into a single one. The generated directory will
# include prebuilts for all the given `target_cpus` and `api_levels` plus
# "PLATFORM". On a host Linux machine, the generated archive will have host
# tools for both Linux/x64 and Linux/arm64 if `sdk_cross_compile_host_tools` is
# true.
#
# It is recommended to use `idk_subbuilds_label_prefix` in order to
# be able to share the sub-builds for the same collection with other idk()
# instances.
#
# The generated directory will go into
# $root_build_dir/sdk/exported/{output_name}
#
# Arguments:
# target_cpus: (required)
# List of target cpu names. This must include the default target_cpu
# value for the current build configuration.
#
# api_levels: (required)
# List of API levels, as strings, for which to include prebuilts, in
# addition to the current (PLATFORM) one.
#
# sdk_collection_label: (required)
# A single label for an sdk_collection() GN target.
#
# idk_subbuilds_label_prefix: (optional)
# The common GN label prefix shared by targets generated by an
# `idk_subbuilds()` instance. This should match the full label of the
# `idk_subbuilds()` target. The `sdk_collection_name` of the sub-builds
# must match the name of the `sdk_collection_label`. The available
# sub-builds must at least include all combinations of `target_cpus` x
# (`api_levels` plus "PLATFORM"). That is, the `target_cpus` and
# `api_levels` parameters passed to `idk_subbuilds()` must at least include
# the values used here.
#
# If provided, these sub-builds will be used.
#
# Otherwise, this template will generate an implicit idk_subbuilds() set
# of targets, but doing so will prevent sharing the sub-build directories
# between different idk() instances that build the same collection for
# different sets of target_cpu / api_level combinations.
#
# idk_subbuilds_dir_prefix: (optional)
# A build directory prefix. Only used when `idk_subbuilds_label_prefix` is provided.
# If provided, this must match the `subbuild_prefix` argument used to define
# the idk_subbuilds_target.
#
# output_name: (optional)
# Name of the directory. Default is target_name
#
# testonly, visibility
# Usual GN meaning.
#
template("idk") {
assert(defined(invoker.target_cpus),
"target_cpus must be defined for $target_name")
assert(defined(invoker.api_levels),
"api_levels must be defined for $target_name")
assert(defined(invoker.sdk_collection_label),
"sdk_collection_label must be defined for $target_name")
assert(defined(invoker.idk_subbuilds_label_prefix) ||
!defined(invoker.idk_subbuilds_dir_prefix))
# Default output name.
_output_name = target_name
if (defined(invoker.output_name)) {
_output_name = invoker.output_name
}
_non_current_cpus = invoker.target_cpus + [ current_cpu ] - [ current_cpu ]
assert(
invoker.target_cpus != _non_current_cpus,
"The target_cpus argument must include the current target_cpu ($current_cpu): ${invoker.target_cpus}")
# Do the current CPU first. This may not be necessary, but it's what the old
# script did and I want a null-diff.
_target_cpus = [ current_cpu ] + _non_current_cpus
_exported_dir = root_build_dir + "/sdk/exported/${_output_name}"
_exported_dir_manifest = "${_exported_dir}/meta/manifest.json"
_exported_dir_stamp = _exported_dir + ".stamp"
_sdk_collection_name = get_label_info(invoker.sdk_collection_label, "name")
if (defined(invoker.idk_subbuilds_label_prefix)) {
_subbuilds_target_prefix = invoker.idk_subbuilds_label_prefix
if (defined(invoker.idk_subbuilds_dir_prefix)) {
_subbuilds_dir_prefix = invoker.idk_subbuilds_dir_prefix
} else {
# Same default as idk_subbuilds()
_subbuilds_dir_prefix = "idk_subbuild.${_sdk_collection_name}"
}
} else {
# Generate actions for all possible sub-builds.
# Only the ones matching invoker.api_levels and invoker.target_cpus will be used though.
_subbuilds_target = "idk_subbuild_${target_name}"
_subbuilds_dir_prefix = "idk_subbuild.${target_name}"
idk_subbuilds(_subbuilds_target) {
sdk_collection_label = invoker.sdk_collection_label
subbuild_prefix = _subbuilds_dir_prefix
api_levels = invoker.api_levels
target_cpus = invoker.target_cpus
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
}
_subbuilds_target_prefix = ":${_subbuilds_target}"
}
_collection_relative_path = "sdk/exported/${_sdk_collection_name}"
# Targets that must be built before producing the final IDK.
_subbuild_targets = []
# Build directories for each subbuilds that contribute to the IDK, including
# the main build. Note that the contents of the IDK are sensitive to the order
# of this list.
_subbuild_dirs = []
# First, do subbuilds for the default API level.
foreach(target_cpu, _target_cpus) {
if (target_cpu == current_cpu) {
# There is no subbuild for the current CPU - just use the
# `sdk_collection` in the current build.
_subbuild_targets += [ invoker.sdk_collection_label ]
_subbuild_dirs += [ root_build_dir ]
} else {
_subbuild_targets += [ "${_subbuilds_target_prefix}-${target_cpu}" ]
_subbuild_dirs +=
[ "${root_build_dir}/${_subbuilds_dir_prefix}-${target_cpu}" ]
}
}
# Now do them for individual API levels.
foreach(api_level, invoker.api_levels) {
foreach(target_cpu, _target_cpus) {
_subbuild_targets +=
[ "${_subbuilds_target_prefix}-api${api_level}-${target_cpu}" ]
_subbuild_dirs += [ "${root_build_dir}/${_subbuilds_dir_prefix}-api${api_level}-${target_cpu}" ]
}
}
if (target_cpu == current_cpu && invoker.api_levels == []) {
not_needed([
"_subbuilds_dir_prefix",
"_subbuilds_target_prefix",
])
}
if (host_cpu == "x64") {
host_triple_cpu = "x86_64"
} else if (host_cpu == "arm64") {
host_triple_cpu = "aarch64"
} else {
assert(false, "Unrecognized host CPU: ${host_cpu}")
}
if (host_os == "linux") {
host_triple_vendor_os = "unknown-linux-gnu"
} else if (host_os == "fuchsia") {
host_triple_vendor_os = "unknown-fuchsia"
} else {
assert(false, "Unrecognized host OS: ${host_os}")
}
host_triple = "${host_triple_cpu}-${host_triple_vendor_os}"
# Combine all the individual sdk_collection subbuilds and put the result in
# the exported directory.
python_action(target_name) {
binary_label = "//build/sdk/generate_idk"
_schema_validator_tool = "//build/bazel/host:bazel_root_host_tools.json_validator_valico($host_toolchain)"
# Get the path to the schema validator executable.
host_executable = "${host_out_dir}/json_validator_valico"
inputs = [ host_executable ]
deps = _subbuild_targets + [ _schema_validator_tool ]
outputs = [
_exported_dir_manifest,
_exported_dir_stamp,
]
# The exported dir is fully under our control and gets deleted by every
# invocation of this build rule.
hermetic_action_ignored_prefixes = [ _exported_dir ]
depfile = "${target_gen_dir}/${target_name}.d"
args = []
foreach(dir, _subbuild_dirs) {
args += [
"--subbuild-directory",
rebase_path(dir, root_build_dir),
]
}
args += [
"--collection-relative-path",
_collection_relative_path,
"--output-directory",
rebase_path(_exported_dir, root_build_dir),
"--schema-directory",
rebase_path("//build/sdk/meta", root_build_dir),
"--json-validator-path",
rebase_path(host_executable, root_build_dir),
"--stamp-file",
rebase_path(_exported_dir_stamp, root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
"--host-arch",
host_triple,
"--release-version",
sdk_id,
]
foreach(cpu, invoker.target_cpus) {
args += [
"--target-arch",
cpu,
]
}
forward_variables_from(invoker,
[
"assert_no_deps",
"testonly",
"visibility",
])
}
}