blob: 94bb9af779cb06c3f5c97f508e50b377fd011a13 [file]
# Copyright 2022 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/bazel/config/bazel_args.gni")
import("//build/bazel/config/logging.gni")
import("//build/bazel/remote_services.gni")
import("//build/licenses/generated_licenses_spdx.gni")
import("//build/rust/config.gni")
declare_args() {
# Output extra information when Bazel build actions fail.
bazel_verbose_failures = true
# Automatically refreshes compile_commands.json after bazel_actions are built.
#
# NOTE: Enabling will add a several seconds of overhead to the build.
bazel_auto_refresh_compdb = false
}
# Wrap a Bazel command with a GN action.
#
# May only be called on the default_toolchain so as to prevent generating Bazel
# workspace multiple times. Host targets can be built by specifying
# `host = true`.
#
# The caller should pass a list of Bazel target patterns for the
# `bazel build` command, as well as a list Bazel output files relative
# to the workspace's root that will be copied into the
# GN target's target_out_dir by default.
#
# All inputs seen by the Bazel command must be defined in the
# @legacy_ninja_build_outputs Bazel repository, which is populated by
# bazel_input_xxx() targets that must appear as dependencies of the
# //build/bazel:legacy_ninja_build_outputs target.
#
# The bazel-generated files will be copied (possibly hard-linked) into the
# `ninja_base_dir` (which is `target_out_dir` by default) matching the GN
# action for this template call.
#
# This also takes a list of Bazel target patterns, since Bazel does not
# support building specific files, only targets. For now it is up to the
# caller to know exactly which files are generated by Bazel for a given
# set of target patterns.
#
# Args:
# command: (required)
# The Bazel command, e.g. `build`, `run`, `test`...
# See: `bazel help`.
# Type: string.
#
# bazel_inputs: (optional)
# DEPRECATED: Just use `deps` for these.
#
# List of labels to bazel_input_xxx() targets that define
# the set of Ninja-generated inputs that the Bazel build command will
# use. These must be in the dependency tree of
# `//build/bazel:legacy_ninja_build_outputs`. Note that this is only used to
# ensure that said inputs are properly generated by Ninja before this
# action's command is run. The command will be able to see any input
# files exported by the @legacy_ninja_build_outputs Bazel repository,
# as there is no way to restrict them for now.
# Type: list of GN labels.
#
# bazel_targets:
# A list of Bazel target patterns for the `bazel build` command.
# This list cannot be empty since there is no concept of 'default'
# targets in Bazel. Note target sets (i.e. `...`) are not supported.
#
# Relative target names (e.g. ":foo" or "foo:bar") are supported and
# will be resolved relative to the current directory.
#
# Type: list of Bazel target patterns.
#
# ninja_base_dir: (optional)
# A GN path for the base directory used for `ninja` paths in the
# scope items of `copy_outputs`, `directory_outputs`, etc..
# Default value is `target_out_dir`.
#
# copy_outputs: (optional)
# A list of scopes, where each item describes a Bazel output and a
# corresponding Ninja output location (where the Bazel build artifact
# will be copied).
#
# Each scope uses the following format:
#
# {
# bazel = "<bazel_path>"
# ninja = "<ninja_path>"
# }
#
# See technical note below for details about <bazel_path> and <ninja_path>
#
# Type: list of scopes (cannot be empty)
#
# directory_outputs: (optional)
# A list of scopes, where each item describes a Bazel output directory
# (a.k.a. TreeArtifact) and the corresponding Ninja output location where
# it will be copied.
#
# Each scope uses the following schema:
#
# bazel_target (optional)
# A Bazel target label generating the directory. Must be reachable from
# one of the bazel_targets labels. Defaults to bazel_targets[0].
#
# bazel_dir (required)
# A path string to the location of the directory, relative to the
# Bazel workspace. This can use the same substitution expressions
# as `copy_outputs` items.
#
# ninja_dir (required)
# A path string, relative to `ninja_base_dir`, where the
# directory will be recursively copied to. Previous instances are
# replaced, instead of being overwritten, to avoid keeping stale
# files from previous builds.
#
# tracked_files (required)
# A non-empty list of file paths, relative to ninja_dir, corresponding
# to files (not directories), whose timestamps will be used by Ninja
# to determine when to re-run the current action.
#
# These will also be listed as outputs for this GN action, as using
# directories as outputs can lead to incremental build issues in GN/Ninja,
# because timestamps on directories may not correctly represent freshness
# of its contents.
#
# IMPORTANT: For incremental build correctness, these tracked files
# timestamps must always reflect the freshness of the whole directory
# content.
#
# copy_debug_symbols: (optional)
# A boolean flag, set it to true to copy all debug symbols from
# the package's ELF binaries to the top-level ${root_build_dir}/.build-id/
# directory.
#
# package_outputs: (optional)
# A list of scopes describing where to place various Fuchsia package
# related output files. Scope schema is:
#
# package_label: (required)
# A bazel label to a fuchsia_package() or fuchsia_test_package()
# target. This target must be reachable from one of the labels
# listed in the top-level bazel_targets argument.
#
# archive: (required)
# output path for the package's archive, relative to `ninja_base_dir`.
#
# manifest: (optional)
# output path for the package's manifest file, relative to `ninja_base_dir`.
#
# copy_debug_symbols: (optional)
# A boolean flag, set it to true to copy all debug symbols from
# the package's ELF binaries to the top-level ${root_build_dir}/.build-id/
# directory.
#
# final_symlink_outputs: (optional)
# A list of scopes describing symlink locations, relative to the Ninja build
# directory, pointing to Bazel artifacts directly. This is similar
# to copy_outputs, except that the `ninja` path points to a symlink location
# in the Ninja build directory.
#
# IMPORTANT: This should only be used for "final" targets of the Ninja build
# graph, i.e. ones that are never used as input for other Ninja commands, since
# the timestamp in the Bazel output base, which the symlink point to, are never
# guaranteed to be consistent.
#
# This is useful to use the symlinks after the build complete.
#
# NOTE: This feature is a special case and is not available to wrappers
# like `bazel_build_action()` intentionally, in order to limit its usage.
#
# extra_bazel_args: (optional)
# A list extra command line arguments to pass to Bazel.
# Type: list of string.
#
# filter_bazel_info_logs: (optional)
# When true (the default value), INFO level logs are filtered from Bazel.
# INFO level logs from Bazel are usually not interesting during Ninja
# invocations.
# Type: boolean
# Default: true
#
# remote_build: (optional)
# Set this to false to override the global default `enable_bazel_remote_rbe`
# setting which controls whether the underlying bazel invocation
# will build remotely using RBE.
# Type: boolean
# Default: `enable_bazel_remote_rbe` (global)
#
# include_host_tools_licenses: (optional)
# Set this to true to include the licenses of host tool dependencies in
# @gn_targets//:all_licenses.spdx.json.
# Type: boolean
# Default: false
#
# ignore_license_collection_errors: (optional)
# Set this to true to ignore errors when collecting license requirements
# from dependencies.
# Type: boolean
# Default: false
#
# no_sdk: (optional)
# Set this to true to run a Bazel command to build artifacts that do not
# depend on the Fuchsia IDK or SDK. This makes these targets available to
# the GN graph early during the build. Must be true if `host` is true.
# Type: boolean
# Default: false
#
# host: (optional)
# Set this to true to run a Bazel command to build host artifacts.
# Requires `no_sdk = true`.
# Type: boolean
# Default: false
#
# bazel_platform: (optional)
# Overwrite the `--platforms` flag when building with Bazel.
# Must match one of the available platforms defined in
# //build/bazel/platforms/BUILD.bazel.
# When not set, the configured platform from the .bazelrc will be used.
#
# NOTE: There is no guarantee that your chosen platform will work with the
# `--config` applied, so use this parameter with caution.
#
# Type: string
#
# deps:
# metadata:
# check_for_output_dir_leaks:
# testonly:
# visibility:
# Usual GN meaning.
#
#
# TECHNICAL NOTE ON BAZEL OUTPUTS:
#
# Bazel places its build artifacts under directories that are specific to
# the Bazel build configuration. In practice, these will be different based
# on the current GN toolchain instance where the bazel_action() target
# is defined.
#
# Because the exact Bazel config directories are hard to predict, Bazel
# creates (or updates) a symlink named `bazel-bin` in the main workspace
# directory. This symlink points to the correct config-specific directory,
# and build artifacts are then reachable as
# "$BAZEL_WORKSPACE/bazel-bin/<bazel_target_package>/<output_files>"
#
# However, every time a bazel_action() action is run, the value of the
# bazel-bin symlink target *may* change, so these bazel output paths cannot
# be considered stable or valid once the action has completed.
#
# Hence Bazel build outputs must be copied to stable locations in the
# Ninja build directory, by the script invoked by bazel_action().
#
# The `copy_outputs` argument is used to list all Bazel outputs and their
# corresponding Ninja output path. It is a list of scopes whose format
# is:
#
# {
# bazel = "<bazel_path>"
# ninja = "<ninja_path>"
# }
#
# Where <bazel_path> is a Bazel output path, relative to the Bazel workspace
# that looks like "bazel-bin/<bazel_target_package>/<output_file>", and
# where <ninja_path> is an output path relative to the `ninja_base_dir` directory.
#
# Moreover, the <bazel_path> value supports these special substitution
# expressions:
#
# {{BAZEL_TARGET_NAME}}
# Expands to the target name of the first `bazel_targets` label
#
# {{BAZEL_TARGET_PACKAGE}}
# Expands to the package name of the first `bazel_targets` label
# without a // prefix!
#
# {{BAZEL_TARGET_OUT_DIR}}
# Expands to "bazel-bin/{{BAZEL_TARGET_PACKAGE}}"
#
# {{BAZEL_TARGET_OUT_PATH}}
# Expands to {{BAZEL_TARGET_OUT_DIR}}/{{BAZEL_TARGET_NAME}}.
#
template("bazel_action") {
assert(defined(invoker.command), "command must be defined!")
assert(defined(invoker.bazel_targets), "bazel_targets must be defined!")
assert(invoker.bazel_targets != [], "bazel_targets cannot be empty!")
_no_sdk = defined(invoker.no_sdk) && invoker.no_sdk
_build_for_host = defined(invoker.host) && invoker.host
assert(!_build_for_host || _no_sdk,
"`no_sdk` must true when `host` is true. ")
# Limit usage of `bazel_platform` to host platforms to minimize chances of
# misuse. It's created to support cross-compiling SDK host tools.
if (defined(invoker.bazel_platform)) {
assert(_build_for_host,
"`bazel_platform` is only supported when `host` is true.")
}
_copy_outputs = []
if (defined(invoker.copy_outputs)) {
_copy_outputs = invoker.copy_outputs
}
_directory_outputs = []
if (defined(invoker.directory_outputs)) {
_directory_outputs = invoker.directory_outputs
}
_package_outputs = []
if (defined(invoker.package_outputs)) {
_package_outputs = invoker.package_outputs
}
_final_symlink_outputs = []
if (defined(invoker.final_symlink_outputs)) {
_final_symlink_outputs = invoker.final_symlink_outputs
}
assert(
_copy_outputs != [] || _directory_outputs != [] ||
_package_outputs != [] || _final_symlink_outputs != [],
"At least one of `copy_outputs`, `directory_outputs` or `package_outputs` must be a non-empty list!")
_has_file_outputs = false
_has_directory_outputs = false
_has_package_outputs = false
_has_final_symlink_outputs = false
_ninja_base_dir = target_out_dir
if (defined(invoker.ninja_base_dir)) {
_ninja_base_dir = invoker.ninja_base_dir
}
_bazel_targets = invoker.bazel_targets
# Collect all outputs into a single list of scopes with different schemas.
# All of them have a "type" string key, and a "bazel_target" label string.
_all_outputs = []
foreach(entry, _copy_outputs) {
assert("$entry" != entry,
"`copy_outputs` items must be scopes, string found: \"$entry\"")
assert(defined(entry.bazel),
"`copy_outputs` scope requires bazel key: $entry")
assert(defined(entry.ninja),
"`copy_outputs` scope requires ninja key: $entry")
_bazel_target = _bazel_targets[0]
if (defined(entry.bazel_target)) {
_bazel_target = entry.bazel_target
}
foreach(path, [ entry.bazel ]) {
assert(rebase_path(path, "//") != path,
"bazel output path must be relative: $path")
assert(string_replace("XX$path", "XX-", "") == "XX$path",
"bazel output path cannot begin with dash: $path")
if (string_replace(path, "{{BAZEL_TARGET_", "") != path) {
_bazel_target_name = get_label_info(_bazel_target, "name")
_bazel_target_package =
rebase_path(get_label_info(_bazel_target, "dir"), "//")
_bazel_target_out_dir = "bazel-bin/" + _bazel_target_package
path = string_replace(path, "{{BAZEL_TARGET_NAME}}", _bazel_target_name)
path = string_replace(path,
"{{BAZEL_TARGET_PACKAGE}}",
_bazel_target_package)
path = string_replace(path,
"{{BAZEL_TARGET_OUT_DIR}}",
_bazel_target_out_dir)
path = string_replace(path,
"{{BAZEL_TARGET_OUT_PATH}}",
"${_bazel_target_out_dir}/${_bazel_target_name}")
}
# In case of typo with a substitution (e.g. writing {{BAZEL_TARGET_O_DIR}})
# GN will complain with an error but will not display the problematic
# so use an assert to provide a user-friendly message.
assert(string_replace(path, "{{", "") == path,
"Unsupported substitution in Bazel output path: $path")
_bazel_file = path
}
_all_outputs += [
{
type = "file"
bazel_target = get_label_info(_bazel_target, "label_no_toolchain")
bazel_file = _bazel_file
ninja_file = "${_ninja_base_dir}/${entry.ninja}"
},
]
_has_file_outputs = true
}
foreach(entry, _directory_outputs) {
assert("$entry" != entry,
"`directory_outputs` items must be scopes, string found: \"$entry\"")
assert(defined(entry.bazel_dir),
"`directory_outputs` scope requires bazel_dir key: $entry")
assert(defined(entry.ninja_dir),
"`directory_outputs` scope requires ninja_dir key: $entry")
assert(defined(entry.tracked_files),
"`directory_outputs` scope requires tracked_files key: $entry")
_bazel_target = _bazel_targets[0]
if (defined(entry.bazel_target)) {
_bazel_target = entry.bazel_target
}
foreach(path, [ entry.bazel_dir ]) {
assert(rebase_path(path, "//") != path,
"bazel output path must be relative: $path")
assert(string_replace("XX$path", "XX-", "") == "XX$path",
"bazel output path cannot begin with dash: $path")
if (string_replace(path, "{{BAZEL_TARGET_", "") != path) {
_bazel_target_name = get_label_info(_bazel_target, "name")
_bazel_target_package =
rebase_path(get_label_info(_bazel_target, "dir"), "//")
_bazel_target_out_dir = "bazel-bin/" + _bazel_target_package
path = string_replace(path, "{{BAZEL_TARGET_NAME}}", _bazel_target_name)
path = string_replace(path,
"{{BAZEL_TARGET_PACKAGE}}",
_bazel_target_package)
path = string_replace(path,
"{{BAZEL_TARGET_OUT_DIR}}",
_bazel_target_out_dir)
path = string_replace(path,
"{{BAZEL_TARGET_OUT_PATH}}",
"${_bazel_target_out_dir}/${_bazel_target_name}")
}
# In case of typo with a substitution (e.g. writing {{BAZEL_TARGET_O_DIR}})
# GN will complain with an error but will not display the problematic
# so use an assert to provide a user-friendly message.
assert(string_replace(path, "{{", "") == path,
"Unsupported substitution in Bazel output path: $path")
_bazel_dir = path
}
_all_outputs += [
{
type = "directory"
bazel_target = get_label_info(_bazel_target, "label_no_toolchain")
bazel_dir = _bazel_dir
ninja_dir = "${_ninja_base_dir}/${entry.ninja_dir}"
copy_debug_symbols =
defined(entry.copy_debug_symbols) && entry.copy_debug_symbols
tracked_files = entry.tracked_files
},
]
_has_directory_outputs = true
}
foreach(entry, _package_outputs) {
assert("$entry" != entry,
"`package_outputs` items must be scopes, string found: \"$entry\"")
assert(defined(entry.package_label),
"`package_outputs` scope requires package_label key: $entry")
_archive = ""
if (defined(entry.archive)) {
_archive = "${_ninja_base_dir}/${entry.archive}"
}
_manifest = ""
if (defined(entry.manifest)) {
_manifest = "${_ninja_base_dir}/${entry.manifest}"
}
_all_outputs += [
{
type = "package"
bazel_target = get_label_info(entry.package_label, "label_no_toolchain")
ninja_archive = _archive
ninja_manifest = _manifest
copy_debug_symbols =
defined(entry.copy_debug_symbols) && entry.copy_debug_symbols
},
]
_has_package_outputs = true
}
foreach(entry, _final_symlink_outputs) {
assert(
"$entry" != entry,
"`final_symlink_outputs` items must be scopes, string found: \"$entry\"")
assert(defined(entry.bazel),
"`final_symlink_outputs` scope requires bazel key: $entry")
assert(defined(entry.ninja),
"`final_symlink_outputs` scope requires ninja key: $entry")
_bazel_target = _bazel_targets[0]
if (defined(entry.bazel_target)) {
_bazel_target = entry.bazel_target
}
foreach(path, [ entry.bazel ]) {
assert(rebase_path(path, "//") != path,
"bazel output path must be relative: $path")
assert(string_replace("XX$path", "XX-", "") == "XX$path",
"bazel output path cannot begin with dash: $path")
if (string_replace(path, "{{BAZEL_TARGET_", "") != path) {
_bazel_target_name = get_label_info(_bazel_target, "name")
_bazel_target_package =
rebase_path(get_label_info(_bazel_target, "dir"), "//")
_bazel_target_out_dir = "bazel-bin/" + _bazel_target_package
path = string_replace(path, "{{BAZEL_TARGET_NAME}}", _bazel_target_name)
path = string_replace(path,
"{{BAZEL_TARGET_PACKAGE}}",
_bazel_target_package)
path = string_replace(path,
"{{BAZEL_TARGET_OUT_DIR}}",
_bazel_target_out_dir)
path = string_replace(path,
"{{BAZEL_TARGET_OUT_PATH}}",
"${_bazel_target_out_dir}/${_bazel_target_name}")
}
# In case of typo with a substitution (e.g. writing {{BAZEL_TARGET_O_DIR}})
# GN will complain with an error but will not display the problematic
# so use an assert to provide a user-friendly message.
assert(string_replace(path, "{{", "") == path,
"Unsupported substitution in Bazel output path: $path")
_bazel_file = path
}
_all_outputs += [
{
type = "final_symlink"
bazel_target = get_label_info(_bazel_target, "label_no_toolchain")
bazel_file = _bazel_file
ninja_file = "${_ninja_base_dir}/${entry.ninja}"
},
]
_has_final_symlink_outputs = true
}
# Write the log of build events to a target-specific file.
# See https://bazel.build/remote/bep for details.
# For now, produce in JSON output since we lack a tool to convert from
# binary to other formats in the tree.
_bazel_build_events_log_json =
"$target_out_dir/$target_name.bazel_events.log.json"
_rebased_bazel_build_events_log_json =
rebase_path(_bazel_build_events_log_json, root_build_dir)
_bazel_build_files = []
_bazel_targets = []
foreach(label, invoker.bazel_targets) {
dir = get_label_info(label, "dir")
name = get_label_info(label, "name")
assert(get_path_info(dir, "file") != "...",
"`...` is not supported in bazel_targets")
_bazel_build_files += [ "${dir}/BUILD.bazel" ]
_bazel_targets += [ "${dir}:${name}" ]
}
# A group to depend on all bazel_input_xxx() dependencies.
_bazel_inputs_group_target = "$target_name.bazel_inputs"
group(_bazel_inputs_group_target) {
forward_variables_from(invoker,
[
"deps",
"testonly",
])
if (defined(invoker.bazel_inputs)) {
if (!defined(deps)) {
deps = []
}
deps += invoker.bazel_inputs
}
visibility = [ ":*" ]
}
# Generate a manifest file that references all transitive bazel_input_file()
# and bazel_input_directory() dependencies from 'deps' or 'bazel_inputs'.
#
# These are passed to bazel_action.py to populate the @gn_targets external
# repository with symlinks and filegroups().
#
_gn_targets_repository_manifest =
"$target_out_dir/${target_name}.gn_targets_manifest.json"
_gn_targets_repository_manifest_target = "${target_name}.gn_targets"
generate_gn_targets_repository_manifest(
_gn_targets_repository_manifest_target) {
forward_variables_from(invoker, [ "testonly" ])
output = _gn_targets_repository_manifest
deps = [ ":${_bazel_inputs_group_target}" ]
}
# Generate an SPDX file that contains license information for all
# dependencies of this bazel_action() GN target, this will be exposed
# through the special @gn_targets//all_licenses_spdx_json, which should
# be used in product-specific build rules instead of
# @legacy_ninja_build_outputs//:all_bazel_inputs_licenses_spdx_json
_all_licenses_spdx_target = "${target_name}.all_licenses_spdx"
_all_licenses_spdx_file =
"$target_out_dir/${target_name}.all_licenses.spdx.json"
generated_licenses_spdx(_all_licenses_spdx_target) {
forward_variables_from(invoker, [ "testonly" ])
target = ":${_bazel_inputs_group_target}"
output = _all_licenses_spdx_file
spdx_root_package_name = "Fuchsia"
debug_hints = true
include_host_tools = defined(invoker.include_host_tools_licenses) &&
invoker.include_host_tools_licenses
ignore_collection_errors =
defined(invoker.ignore_license_collection_errors) &&
invoker.ignore_license_collection_errors
visibility = [ ":*" ]
}
# Location of the @gn_targets repository for this Bazel invocation.
# This points to a directory that is generated by //build/regenerator
# before the build, to allow for Bazel queries to be performed as soon as
# possible.
_gn_targets_repository_path = "${target_out_dir}/${target_name}.gn_targets"
# A file that will contain a mapping from Bazel artifacts to Ninja outputs.
_path_mapping = "${target_out_dir}/${target_name}.path_mapping"
_rebased_path_mapping = rebase_path(_path_mapping, root_build_dir)
# A file that will receive the exact Bazel command invoked by the
# bazel_action.py script.
_bazel_command_file = "${target_out_dir}/${target_name}.bazel_command.sh"
_rebased_bazel_command_file = rebase_path(_bazel_command_file, root_build_dir)
# A file that will receive the explain output from the bazel_action.py script.
#
# The output is from dependency checker in Bazel build's execution phase to
# explain, for each build step, either why it is being executed, or that it is
# up-to-date.
#
# NOTE: This file will only include explain output from the `build` command,
# not other commands like `query`.
_bazel_explain_file = "${target_out_dir}/${target_name}.bazel_explain.txt"
_rebased_bazel_explain_file = rebase_path(_bazel_explain_file, root_build_dir)
_timings_file = "${target_out_dir}/${target_name}.bazel_action_timings.json"
_rebased_timings_file = rebase_path(_timings_file, root_build_dir)
_debug_symbols_manifest =
"${target_out_dir}/${target_name}.debug_symbols.json"
_rebased_debug_symbols_manifest =
rebase_path(_debug_symbols_manifest, root_build_dir)
_rust_project_json = "${target_out_dir}/${target_name}.rust-project.json"
_rebased_rust_project_json = rebase_path(_rust_project_json, root_build_dir)
action(target_name) {
forward_variables_from(invoker,
[
"deps",
"check_for_output_dir_leaks",
"testonly",
"visibility",
])
mnemonic = "BAZEL"
script = "//build/bazel/scripts/bazel_action.py"
inputs = [
"//build/bazel/toplevel.MODULE.bazel",
"//build/bazel/templates/template.platform_mappings",
"//build/bazel/templates/template.bazel.sh.config",
"//build/bazel/templates/template.bazelrc",
# Imported by bazel_action.py
"//build/api/debug_symbols.py",
"//build/bazel/scripts/bazel_compdb_utils.py",
"//build/bazel/scripts/bazel_rust_analyzer_utils.py",
"//build/bazel/scripts/build_utils.py",
"//build/bazel/scripts/stdio_redirection.py",
"//build/bazel/scripts/thread_pool_helpers.py",
"//build/bazel/scripts/workspace_utils.py",
"//build/bazel/wrapper.bazel.sh",
] + _bazel_build_files
if (defined(invoker.inputs)) {
inputs += invoker.inputs
}
depfile = "${target_gen_dir}/${target_name}.d"
outputs = [
_path_mapping,
_bazel_command_file,
_bazel_explain_file,
_debug_symbols_manifest,
_rust_project_json,
_timings_file,
]
# Write stamp files for every Bazel target executed by this bazel_action.
# Note these stamps are written to paths based on Bazel target labels.
# This makes sure the same Bazel target is not claimed by multiple
# bazel_actions in the same build graph, which breaks Ninja noop checks,
# see http://b/353897478. In case it happens, GN will fail complaining about
# multiple targets sharing the same output.
_dedupe_stamps = []
foreach(_bazel_target, _bazel_targets) {
_out_dir = get_label_info(_bazel_target, "target_out_dir")
_bazel_label = get_label_info(_bazel_target, "name")
_dedupe_suffix = "${current_os}_${current_cpu}"
if (_build_for_host) {
_dedupe_suffix = "${host_os}_${host_cpu}"
}
if (defined(invoker.bazel_platform)) {
_dedupe_suffix = invoker.bazel_platform
}
_dedupe_stamps += [ "${_out_dir}/${_bazel_label}.${_dedupe_suffix}.bazel_target_can_only_be_referenced_by_one_bazel_action" ]
}
outputs += _dedupe_stamps
args = [
"--build-dir",
rebase_path(root_build_dir, root_build_dir),
"--fuchsia-dir",
rebase_path("//", root_build_dir),
"--command",
invoker.command,
"--gn-target-label",
get_label_info(":$target_name", "label_no_toolchain"),
"--gn-targets-repository-dir",
rebase_path(_gn_targets_repository_path, root_build_dir),
"--bazel-targets",
] + _bazel_targets +
[
"--depfile",
rebase_path(depfile, root_build_dir),
"--command-file",
_rebased_bazel_command_file,
"--timings-file",
_rebased_timings_file,
"--explain-file",
_rebased_bazel_explain_file,
"--path-mapping",
_rebased_path_mapping,
"--debug-symbols-manifest",
_rebased_debug_symbols_manifest,
"--rust-sysroot",
rebased_rustc_prefix,
"--rust-project-json",
_rebased_rust_project_json,
"--stamp-files",
]
foreach(s, _dedupe_stamps) {
args += [ rebase_path(s, root_build_dir) ]
}
if (bazel_verbose_failures) {
args += [ "--verbose_failures" ]
}
if (bazel_auto_refresh_compdb) {
_compdb_file =
"${target_out_dir}/${target_name}.bazel_compile_commands.json"
_rebased_compdb_file = rebase_path(_compdb_file, root_build_dir)
outputs += [ _compdb_file ]
args += [
"--compdb-file",
_rebased_compdb_file,
]
}
if (_has_file_outputs) {
args += [ "--file-outputs" ]
foreach(output, _all_outputs) {
if (output.type == "file") {
args += [
output.bazel_file,
rebase_path(output.ninja_file, root_build_dir),
]
outputs += [ output.ninja_file ]
}
}
}
if (_has_directory_outputs) {
foreach(output, _all_outputs) {
if (output.type == "directory") {
args += [
"--directory-outputs",
output.bazel_dir,
rebase_path(output.ninja_dir, root_build_dir),
"${output.copy_debug_symbols}",
] + output.tracked_files
assert(output.tracked_files != [],
"Directory outputs require tracked files.")
foreach(tracked_file, output.tracked_files) {
outputs += [ "${output.ninja_dir}/${tracked_file}" ]
}
}
}
}
if (_has_package_outputs) {
# These starlark script are used to perform queries to get provider values
# for each package.
inputs += [
"//build/bazel/starlark/FuchsiaPackageInfo_archive_and_manifest.cquery",
"//build/bazel/starlark/FuchsiaDebugSymbolInfo_debug_symbol_dirs.cquery",
]
foreach(output, _all_outputs) {
if (output.type == "package") {
_archive_arg = "NONE"
if (output.ninja_archive != "") {
outputs += [ output.ninja_archive ]
_archive_arg = rebase_path(output.ninja_archive, root_build_dir)
}
_manifest_arg = "NONE"
if (output.ninja_manifest != "") {
outputs += [ output.ninja_manifest ]
_manifest_arg = rebase_path(output.ninja_manifest, root_build_dir)
}
_copy_debug_symbols = output.copy_debug_symbols
args += [
"--package-outputs",
output.bazel_target,
_archive_arg,
_manifest_arg,
"${output.copy_debug_symbols}",
]
}
}
}
if (_has_final_symlink_outputs) {
args += [ "--final-symlink-outputs" ]
foreach(output, _all_outputs) {
if (output.type == "final_symlink") {
args += [
output.bazel_file,
rebase_path(output.ninja_file, root_build_dir),
]
outputs += [ output.ninja_file ]
}
}
}
if (invoker.command == "build") {
outputs += [ _bazel_build_events_log_json ]
args += [
"--bazel-build-events-log-json",
_rebased_bazel_build_events_log_json,
]
}
args += [ "--" ]
if (bazel_quiet) {
args += [ "--config=quiet" ]
} else {
# Disable INFO lines and printing results, this makes Bazel output much
# less chatty when invoked from Ninja. https://fxbug.dev/42077198
args += [ "--ui_event_filters=-info" ]
if (invoker.command != "query") {
# The --show_result option is not supported by bazel query.
args += [ "--show_result=0" ]
}
}
if (_build_for_host) {
args += [ "--config=host_config_args" ]
if (defined(invoker.bazel_platform)) {
args +=
[ "--platforms=//build/bazel/platforms:${invoker.bazel_platform}" ]
} else {
args += [ "--platforms=//build/bazel/platforms:host" ]
}
} else {
# Since this template can only be used on the default toolchain, the
# platform is always Fuchsia.
args += [ "--config=fuchsia_config_args" ]
if (defined(invoker.bazel_platform)) {
args +=
[ "--platforms=//build/bazel/platforms:${invoker.bazel_platform}" ]
} else {
args += [ "--platforms=//build/bazel/platforms:fuchsia_${current_cpu}" ]
}
}
# When remote builds are enabled, append the right build arguments.
# These must appear on the Bazel command-line otherwise remote builds
# will fail on infra (the reason being that the Bazel wrapper script
# detects these options to add infra-specific proxy configuration
# the the final command-line).
if (enable_bazel_remote_rbe) {
_remote_build = !defined(invoker.remote_build) || invoker.remote_build
if (_remote_build) {
# It is assumed that remote builds are enabled for both the default
# and host GN toolchains at the same time.
args += bazel_args.remote_build
}
} else {
# Remote builds are globally disabled, so ignore this value if it exists.
not_needed(invoker, [ "remote_build" ])
}
# Similarly, this config must appear on the command-line and cannot
# be part of --config=host or --config=fuchsia.
if (bazel_upload_build_events != "") {
args += [ "--config=$bazel_upload_build_events" ]
}
# --config=quiet is always used by default, but it is possible
# to disable that by setting filter_bazel_info_logs to false.
_filter_bazel_info_logs = true
if (defined(invoker.filter_bazel_info_logs)) {
_filter_bazel_info_logs = invoker.filter_bazel_info_logs
}
if (!_filter_bazel_info_logs) {
args += [ "--config=verbose" ]
}
metadata = {
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
# Hint to ninja that this action can take about a minute, so that it's
# appropriately weighted in the calculation of the critical path for a
# build.
ninja_edge_weights =
[ rebase_path(outputs[0], root_build_dir) + ",60000" ]
if (invoker.command == "build") {
# Used by //:bazel_build_events_logs Build API module.
bazel_build_events_log = [
{
gn_label = get_label_info(":$target_name", "label_no_toolchain")
build_events_log = _rebased_bazel_build_events_log_json
format = "json"
},
]
# Used by //:bazel_build_actions target.
bazel_build_actions_barrier = []
bazel_build_actions = [
# LINT.IfChange(bazel_build_actions)
{
gn_target = get_label_info(":$target_name", "label_no_toolchain")
bazel_targets = _bazel_targets
no_sdk = _no_sdk
gn_targets_dir =
rebase_path(_gn_targets_repository_path, root_build_dir)
gn_targets_manifest =
rebase_path(_gn_targets_repository_manifest, root_build_dir)
gn_targets_licenses_spdx =
rebase_path(_all_licenses_spdx_file, root_build_dir)
debug_symbols_manifest = _rebased_debug_symbols_manifest
bazel_command_file = _rebased_bazel_command_file
bazel_explain_file = _rebased_bazel_explain_file
path_mapping = _rebased_path_mapping
timings_file = _rebased_timings_file
build_events_log_json = _rebased_bazel_build_events_log_json
bazel_rust_project_json = _rebased_rust_project_json
if (bazel_auto_refresh_compdb) {
bazel_compdb_file = _rebased_compdb_file
}
},
# LINT.ThenChange(//BUILD.gn:bazel_build_actions)
]
# Used by //:debug_symbols
debug_symbol_manifests = [
{
label = get_label_info(":$target_name", "label_no_toolchain")
manifest = _rebased_debug_symbols_manifest
},
]
}
}
if (defined(invoker.extra_bazel_args)) {
args += invoker.extra_bazel_args
}
if (!defined(deps)) {
deps = []
}
deps += [
# This dependency exists to ensure that this manifest is generated
# at `gn gen` time
":${_gn_targets_repository_manifest_target}",
# This dependency exists to ensure the SPDX file is updated if needed.
# //build/regenerator will write a placeholder file at the same location
# with a timestamp in the distant past, as this is needed to perform
# Bazel queries before calling Ninja. However, building Bazel targets
# require a valid license file.
":${_all_licenses_spdx_target}",
# In addition to checking whether the action is allowed, this dependency
# ensures that the template is being used on the default toolchain.
"//build/bazel:bazel_action_allowlist",
]
if (!_no_sdk) {
deps += [
# TODO(https://fxbug.dev/333907192): Remove this IDK.
"//build/bazel:fuchsia_internal_only_idk.hash",
# The IDK repository is generated by regenerator.py but contains
# symlinks to Ninja artifact locations. Ensure the ninja artifacts
# exist.
"//sdk:ensure_bazel_in_tree_idk_is_populated_for_bazel_action",
]
}
# Using the console pool prevents concurrent bazel build actions to run
# (otherwise the `bazel-bin` symlink target would become unpredictable
# resulting in erroneous outputs or errors), as well as allow Bazel to
# print its progress on smart terminals when `fx build` is invoked
# from one, which is handy to follow long-lasting commands.
pool = "//:console($default_toolchain)"
# This action definitely cannot be hermetic. Callers should add
# themselves to the //build:non_hermetic_deps visibility list.
hermetic_deps = false
# The build events log contains absolute paths written by Bazel!
check_for_output_dir_leaks = false
}
}