blob: 4eb155181ffeef057228a28c26d5afbb52b3b287 [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/logging.gni")
import("//build/bazel/remote_services.gni")
import("//build/licenses/generated_licenses_spdx.gni")
import("//build/rust/config.gni")
declare_args() {
# 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 targets 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 targets.
#
# 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`.
#
# update_rust_project: (optional)
# A boolean (default=false) to update rust_project.json with the Rust
# targets contained within this Bazel action.
#
# 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`.
#
# 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.
#
# 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
#
# bazel_config:
# String matching one of the following:
# * "host": Build host artifacts.
# * "fuchsia_platform": Build Fuchsia platform artifacts.
# * "fuchsia_sdk": Build Fuchsia platform artifacts using the
# in-tree Bazel SDK. Targets are not available to the GN graph until the
# entire SDK has been built.
#
# 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") {
# Bazel actions can only be run in the default toolchain, so no-op the
# template since trying to enforce this in all the BUILD.gn files themselves
# is currently infeasible.
if (current_toolchain == default_toolchain) {
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!")
assert(defined(invoker.bazel_config), "bazel_config must be defined!")
# Calculate the correct Bazel platform to use.
if (invoker.bazel_config == "host") {
_bazel_platform_config = "host_config_args"
_bazel_platform_label = "//build/bazel/platforms:host"
_no_sdk = true
_build_for_host = true
} else if (invoker.bazel_config == "fuchsia_platform") {
_bazel_platform_config = "fuchsia_config_args"
_bazel_platform_label =
"//build/bazel/platforms:fuchsia_platform_${current_cpu}"
_no_sdk = true
_build_for_host = false
} else if (invoker.bazel_config == "fuchsia_sdk") {
_bazel_platform_config = "fuchsia_config_args"
_bazel_platform_label =
"//build/bazel/platforms:fuchsia_sdk_${current_cpu}"
_no_sdk = false
_build_for_host = false
} else {
assert(
false,
"Unrecognized `bazel_config` value: '${invoker.bazel_config}'. Use: 'host' for host artifacts, 'fuchsia_platform' for platform artifacts, or 'fuchsia_sdk' when using the Bazel SDK.")
}
if (defined(invoker.bazel_platform)) {
_bazel_platform_label =
"//build/bazel/platforms:${invoker.bazel_platform}"
}
_update_rust_project =
defined(invoker.update_rust_project) && invoker.update_rust_project
_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_package_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}"
},
]
}
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
assert(entry.tracked_files != [],
"Directory outputs require tracked files.")
tracked_files = entry.tracked_files
},
]
}
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}"
}
_all_outputs += [
{
type = "package"
bazel_target =
get_label_info(entry.package_label, "label_no_toolchain")
ninja_archive = _archive
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}"
},
]
}
# 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_gn_target_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 receive the exact Bazel command invoked by the
# bazel_gn_targets_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_gn_target_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)
if (_update_rust_project) {
_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",
])
if (!defined(deps)) {
deps = []
}
mnemonic = "BAZEL"
script = "//build/bazel/scripts/bazel_gn_target_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",
# TODO(https://fxbug.dev/475142618): Remove this once change in rust.BUILD.bazel
# correctly trigger bazel action rebuilds.
"//build/bazel/toolchains/rust/rust.BUILD.bazel",
# Starlark query files
"//build/bazel/starlark/FuchsiaPackageInfo_archive.cquery",
# Imported by bazel_gn_target_action.py
# LINT.IfChange(bazel_gn_target_imports)
"//build/api/debug_symbols.py",
"//build/bazel/scripts/bazel_action_impl.py",
"//build/bazel/scripts/bazel_ninja_delayed_actions.py",
"//build/bazel/scripts/bazel_action_file_copy_utils.py",
"//build/bazel/scripts/bazel_action_utils.py",
"//build/bazel/scripts/bazel_compdb_utils.py",
"//build/bazel/scripts/bazel_label_mapper.py",
"//build/bazel/scripts/bazel_rust_analyzer_utils.py",
"//build/bazel/scripts/build_utils.py",
"//build/bazel/scripts/thread_pool_helpers.py",
"//build/bazel/scripts/workspace_utils.py",
#LINT.ThenChange(//build/bazel/scripts/bazel_gn_target_action.py:imports)
# Imported by bazel_action_impl.py
#LINT.IfChange(bazel_action_impl_imports)
"//build/bazel/scripts/bazel_action_file_copy_utils.py",
"//build/bazel/scripts/bazel_action_utils.py",
"//build/bazel/scripts/bazel_source_path_mapper.py",
"//build/bazel/scripts/build_utils.py",
"//build/bazel/scripts/stdio_redirection.py",
#LINT.ThenChange(//build/bazel/scripts/bazel_action_impl.py:imports)
# The shell script used to execute Bazel itself.
"//build/bazel/wrapper.bazel.sh",
] + _bazel_build_files
if (defined(invoker.inputs)) {
inputs += invoker.inputs
}
depfile = "${target_gen_dir}/${target_name}.d"
outputs = [
_bazel_command_file,
_bazel_explain_file,
_debug_symbols_manifest,
_timings_file,
]
if (_update_rust_project) {
outputs += [ _rust_project_json ]
}
# bazel_gn_target_action.py always checks the rbe_settings.json file to
# see if RBE is enabled or not.
inputs += [ "${root_build_dir}/rbe_settings.json" ]
deps += [ "//build/rbe:rbe_settings.json" ]
# bazel_gn_target_action.py always checks global_bazel_args.json for
# configuration of extra global arguments
inputs += [ "${root_build_dir}/bazel_args/global_args.json" ]
deps += [ "//build/bazel/config:global_args.json" ]
# 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_stamp_lookup = []
foreach(_bazel_target, _bazel_targets) {
_out_dir = get_label_info(_bazel_target, "target_out_dir")
_bazel_label = get_label_info(_bazel_target, "name")
if (_build_for_host) {
_dedupe_suffix = "${host_os}_${host_cpu}"
} else {
_dedupe_suffix = "${current_os}_${current_cpu}"
}
if (defined(invoker.bazel_platform)) {
_dedupe_suffix = invoker.bazel_platform
}
_stamp_path = "${_out_dir}/${_bazel_label}.${_dedupe_suffix}.bazel_target_can_only_be_referenced_by_one_bazel_action"
outputs += [ _stamp_path ]
_dedupe_stamp_lookup += [
{
bazel_target = _bazel_target
stamp_path = _stamp_path
},
]
}
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"),
"--bazel-platform-label",
_bazel_platform_label,
"--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,
"--debug-symbols-manifest",
_rebased_debug_symbols_manifest,
]
if (_update_rust_project) {
args += [
"--rust-sysroot",
rebased_rustc_prefix,
"--rust-project-json",
_rebased_rust_project_json,
]
}
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,
]
}
# Set the expected outputs
foreach(output, _all_outputs) {
if (output.type == "file") {
outputs += [ output.ninja_file ]
} else if (output.type == "directory") {
foreach(tracked_file, output.tracked_files) {
outputs += [ "${output.ninja_dir}/${tracked_file}" ]
}
} else if (output.type == "package") {
outputs += [ output.ninja_archive ]
} else if (output.type == "final_symlink") {
outputs += [ output.ninja_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.cquery" ]
}
if (invoker.command == "build") {
outputs += [ _bazel_build_events_log_json ]
args += [
"--bazel-build-events-log-json",
_rebased_bazel_build_events_log_json,
]
}
metadata = {
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
expect_includes_barrier = []
# 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
is_host = _build_for_host
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
timings_file = _rebased_timings_file
build_events_log_json = _rebased_bazel_build_events_log_json
if (_update_rust_project) {
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
},
]
}
# Used by //:bazel_target_infos target.
bazel_target_infos_barrier = []
bazel_target_infos = []
foreach(entry, _all_outputs) {
# LINT.IfChange(bazel_target_infos)
bazel_target_infos += [
{
forward_variables_from(entry,
"*",
[
"ninja_file",
"ninja_archive",
"ninja_dir",
])
# Look up the stamp path for the bazel target that makes these
# outputs.
_stamp_entry = {
}
foreach(_stamp_entry, _dedupe_stamp_lookup) {
if (_stamp_entry.bazel_target == bazel_target) {
stamp_path =
rebase_path(_stamp_entry.stamp_path, root_build_dir)
}
}
# To differentiate different bazel invocations' outputs.
bazel_platform_config = _bazel_platform_config
bazel_platform_label = _bazel_platform_label
# These all need to be rebased from GN paths to outdir-relative
# paths
if (defined(entry.ninja_file)) {
ninja_file = rebase_path(entry.ninja_file, root_build_dir)
}
if (defined(entry.ninja_archive)) {
ninja_archive = rebase_path(entry.ninja_archive, root_build_dir)
}
if (defined(entry.ninja_dir)) {
ninja_dir = rebase_path(entry.ninja_dir, root_build_dir)
}
# The depfile that ninja will read for this action.
ninja_depfile = rebase_path(depfile, root_build_dir)
# The gn_targets_dir that needs to be symlinked into the workspace
# to build the bazel action. This is transitional until this is
# setup on a per-action basis via the bazel_gn_target_action.py
# script and more explicit data about the GN inputs needed by the
# bazel action.
gn_targets_dir =
rebase_path(_gn_targets_repository_path, root_build_dir)
gn_targets_manifest =
rebase_path(_gn_targets_repository_manifest, root_build_dir)
},
]
# LINT.ThenChange(//BUILD.gn:bazel_target_infos,
# //build/bazel/scripts/bazel_action_utils.py:bazel_target_infos)
}
}
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",
]
} else if (invoker.bazel_config == "fuchsia_platform") {
deps += [ "//zircon/public/sysroot_sdk:sysroot_for_fuchsia_platform" ]
}
# 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
}
} else {
not_needed(invoker, "*")
not_needed([ "target_name" ])
}
}