blob: 575eb05455b402a12d9d6135ea48fd71e6601eca [file] [log] [blame] [edit]
# 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/config/fuchsia/platform_version.gni")
import("//build/sdk/config.gni")
import("//build/toolchain/goma.gni")
import("//build/toolchain/rbe.gni")
import("//sdk/config.gni")
# Create a GN directory, and build an `sdk_collection` target for a particular
# target_cpu and api_level by calling `gn gen` and then `ninja` in that
# directory.
template("_subbuild") {
assert(defined(invoker.sdk_collection))
assert(defined(invoker.target_cpu))
assert(defined(invoker.api_level))
assert(defined(invoker.extra_deps))
_build_dir = root_build_dir + "/build-${target_name}"
_build_dir_stamp = _build_dir + ".stamp"
_sdk_collection_dir = get_label_info(invoker.sdk_collection, "dir")
_sdk_collection_name = get_label_info(invoker.sdk_collection, "name")
_sdk_collection = "${_sdk_collection_dir}:${_sdk_collection_name}"
_collection_dir = _build_dir + "/sdk/exported/${_sdk_collection_name}"
_collection_dir_manifest = "${_collection_dir}/meta/manifest.json"
action(target_name) {
script = "//build/sdk/subbuild.py"
outputs = [
_build_dir_stamp,
_collection_dir_manifest,
]
# //sdk:idk_build_tools contains the host tools that must be used in the
# subbuilds. Make sure those (and any extra deps) are built first.
deps = [ "//sdk:idk_build_tools" ] + invoker.extra_deps
args = [
"--stamp-file",
rebase_path(_build_dir_stamp, root_build_dir),
"--sdk-id",
sdk_id,
"--output-build-dir",
rebase_path(_build_dir, root_build_dir),
"--sdk-collection-label",
_sdk_collection,
"--target-cpu",
invoker.target_cpu,
"--api-level",
invoker.api_level,
"--fuchsia-dir",
rebase_path("//", root_build_dir),
"--prebuilt-host-tools-dir",
rebase_path(root_build_dir, _build_dir),
"--compress-debuginfo",
compress_debuginfo,
]
if (sdk_sub_build_parallelism != "") {
args += [
"--parallelism",
"${sdk_sub_build_parallelism}",
]
}
if (sdk_sub_build_max_load_average != "") {
args += [
"--max-load-average",
"${sdk_sub_build_max_load_average}",
]
}
if (cxx_rbe_enable) {
args += [ "--cxx-rbe-enable" ]
}
if (rust_rbe_enable) {
args += [ "--rust-rbe-enable" ]
}
if (use_goma) {
args += [ "--use-goma" ]
if (goma_dir != prebuilt_goma_dir) {
args += [ "--goma-dir=${goma_dir}" ]
}
}
pool = "//sdk:subbuild_pool"
# This script cannot be hermetic.
hermetic_deps = false
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
}
}
# Generate a IDK directory, which merges outputs from different arch-specific
# sub-builds into a single one. The generated directory will include prebuilts
# for all the given `target_cpus`. On a host Linux machine, the generated archive
# will have host tools for both Linux/x64 and Linux/arm64.
#
# 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 integers, to build prebuilts for, in addition to
# the current (HEAD) one.
#
# sdk_collection_label: (required)
# A single label for an sdk_collection() GN target that will be built
# multiple times and merged into the final directory.
#
# 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")
# 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 ($target_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")
_relative_collection_exported_dir = "sdk/exported/${_sdk_collection_name}"
# Targets that must be built before merging the final IDK.
_subbuild_targets = []
# Directories with all the individual IDKs to merge. Note that the contents of
# the merged IDK are sensitive to the order of directories in this list.
_merge_input_dirs = []
# First, do subbuilds for the default API level.
foreach(target_cpu, _target_cpus) {
if (target_cpu == current_cpu) {
# Don't do a subbuild for the current CPU - just depend on the
# `sdk_collection` in the current build.
_subbuild_targets += [ invoker.sdk_collection_label ]
_merge_input_dirs +=
[ "${root_build_dir}/${_relative_collection_exported_dir}" ]
} else {
_subbuild_name = "${target_name}.subbuild-${target_cpu}"
_subbuild(_subbuild_name) {
sdk_collection = invoker.sdk_collection_label
target_cpu = target_cpu
api_level = "0" # Sentinel for "default"
extra_deps = []
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
}
_subbuild_targets += [ ":$_subbuild_name" ]
_merge_input_dirs +=
[ root_build_dir +
"/build-${_subbuild_name}/${_relative_collection_exported_dir}" ]
}
}
# Now do them for individual API levels.
foreach(api_level, invoker.api_levels) {
foreach(target_cpu, _target_cpus) {
_subbuild_name = "${target_name}.subbuild-api${api_level}-${target_cpu}"
# Not all that much changes between API levels, so if we build them all in
# parallel, we could miss out on caching opportunities. But if we do them
# all in series, constant costs associated with each build (e.g. gn gen,
# starting up ninja) are rough.
#
# As a compromise, have the subbuilds for the individual API levels depend
# on the one for the default API level. That way, the subbuilds for the
# individual API levels will largely be able to reuse cached build results
# from the first build we ran. In theory, at least.
_extra_deps = []
if (target_cpu == current_cpu) {
# The "default API level build" for the `current_cpu` is just the
# `sdk_collection` target from the current build.
_extra_deps += [ invoker.sdk_collection_label ]
} else {
_extra_deps += [ ":${target_name}.subbuild-${target_cpu}" ]
}
_subbuild(_subbuild_name) {
sdk_collection = invoker.sdk_collection_label
target_cpu = target_cpu
api_level = "$api_level"
extra_deps = _extra_deps
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
}
_subbuild_targets += [ ":$_subbuild_name" ]
_merge_input_dirs +=
[ root_build_dir +
"/build-${_subbuild_name}/${_relative_collection_exported_dir}" ]
}
}
# Merge together all the individual IDKs and put the result in the exported
# directory. This only contains symlinks to the real files, but can be used
# by other targets that need to use it without a full archive.
action(target_name) {
script = "//scripts/sdk/merger/merge.py"
deps = _subbuild_targets
outputs = [
_exported_dir_manifest,
_exported_dir_stamp,
]
args = []
foreach(input_dir, _merge_input_dirs) {
args += [
"--input-directory",
rebase_path(input_dir, root_build_dir),
]
}
args += [
"--output-directory",
rebase_path(_exported_dir, root_build_dir),
"--stamp-file",
rebase_path(_exported_dir_stamp, root_build_dir),
]
# This script cannot be hermetic.
hermetic_deps = false
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
}
}