blob: 02b61aefe3e18386d5c278ab052ff655b4220d07 [file]
# Copyright 2024 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")
# Build a Bazel target and copy its results back to Ninja.
#
# This template is used to invoke `bazel build <bazel_target>` inside the
# special Bazel workspace set up by the platform build then copy some of its
# outputs back to the Ninja build directory.
#
# This back-copy is necessary because the exact location of Bazel build
# artifacts is essentially unpredictable, but will use hard-copies when
# possible to avoid un-necessary duplications.
#
# All inputs for the Bazel target that come from the Ninja output directory
# must be listed through explicit bazel_input_xxx() GN targets that must
# belong to the transitive list of dependencies for this target.
#
# The bazel-generated files will be copied (possibly hard-linked) into the
# `target_out_dir` matching the GN action for this template call (since
# GN requires that an action's output file be in either target_out_dir
# or target_out_dir).
#
# A depfile will be generated to ensure that all sources seen from the
# Bazel graph become implicit inputs of this GN target, ensuring incremental
# build correctness.
#
# Args:
# bazel_inputs: (optional)
# DEPRECATED, use `deps` instead!
#
# 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_target: (required)
# The Bazel target label passed to the `bazel build` command.
# Relative target names (e.g. ":foo" or "foo:bar") are supported and
# will be resolved relative to the current directory.
#
# Type: Bazel label string.
#
# 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, unless package_outputs is used)
#
# 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 $target_out_dir, where the Bazel
# 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.
#
# package_outputs: (optional)
# A list of scopes describing where to place various Fuchsia package related
# output files. Each list item describes a single package reachable from the
# top-level bazel_target label, with the following schema:
#
# 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 $target_out_dir.
#
# manifest: (optional)
# output path for the package's manifest file, relative to $target_out_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.
#
# 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
#
# deps:
# Usual GN meaning, but any bazel_input_xxx() transitive dependency reachable
# from them will create a corresponding entry in the @gn_targets external
# repository, allowing the Bazel graph to see
#
# 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.
#
# 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 `target_out_dir`
# of the current target.
#
# Moreover, the <bazel_path> value supports these special substitution
# expressions:
#
# {{BAZEL_TARGET_NAME}}
# Expands to the `bazel_target` label.
#
# {{BAZEL_TARGET_PACKAGE}}
# Expands to the package name of `bazel_target` 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_build_action") {
# TODO(https://fxbug.dev/505802054): Update vendor repositories to specify
# the Bazel config when using this template then remove this workaround.
if (!defined(invoker.bazel_config)) {
invoker.bazel_config = "fuchsia_sdk"
}
bazel_action(target_name) {
bazel_targets = [ invoker.bazel_target ]
command = "build"
forward_variables_from(invoker, "*", [ "bazel_target" ])
}
}