blob: 0b4e0916e43dd92fc2144523a163d24dd6771946 [file] [log] [blame]
# 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.
# A set of GN templates to expose Ninja-generated output files as inputs
# to bazel_action() targets. The latter run a `bazel build` command in
# the Bazel workspace setup by the platform build, which cannot access
# the Ninja output directory directly.
#
# A bazel_input_xxx() target defines a mapping from Ninja-generated outputs
# as Bazel filegroups) targets. For historical reasons two distinct
# mechanisms exist:
#
# For full documentation, see the dedicated section in //build/bazel/README.md
#
# - First mechanism: use bazel_input_file() and/or bazel_input_directory()
# to expose output files or even directories.
#
# These templates populate the special @gn_targets// external repository
# with filegroup() targets named "@gn_targets//{gn_dir}:{gn_name}
# where {gn_dir} and {gn_name} reflect the directory and name of the
# bazel_input_xxx() target.
#
# For example, consider an action //src/lib:gen_foo that generates some
# outputs that needs to be exposed to the Bazel graph. This would look like:
#
# # //src/lib/BUILD.bazel
# action("gen_foo") { # generating action
# outputs = [ ... ]
# }
#
# bazel_input_file("foo_outputs") { # expose outputs to Bazel
# generator = ":gen_foo"
# }
#
# Here the "foo_outputs" targets doesn't generate anything, it just records
# information about the output files and what generates them.
#
# Next, one can define a Bazel target that accesses the output files directly
# using the @gn_targets//<gn_label> notation, where <gn_label> matches
# the GN label of the bazel_input_file() target above, as in:
#
# # //src/bar/BUILD.bazel
# process_file(
# name = "process_foo",
# input = "@gn_targets//src/lib:foo_outputs", # use outputs.
# output = "foo_processed_by_bazel",
# )
#
# Invoking Bazel from GN can be done with a bazel_action() target, which must
# list "foo_outputs" as part of its dependencies. For example:
#
# # //src/bar/BUILD.gn
# bazel_action("process_foo_with_bazel") {
# command = "build"
# deps = [ "//src/lib:foo_outputs "]
# copy_outputs = {
# bazel = "{{BAZEL_TARGET_OUT_DIR}}/foo_processed_by_bazel"
# ninja = "foo_final"
# }
# }
#
# Then trying to `fx build //src/bar:process_foo_with_bazel` will do the following:
#
# - Ensure the outputs of //src/lib:gen_foo are up-to-date.
# - Update the content of the @gn_targets repository _before_ launching Bazel.
# - Invoke Bazel with something equivalent to `fx bazel build //src/bar:process_foo`
# - Copy the Bazel build artifact into its final location $BUILD_DIR/obj/src/bar/foo_final
# - Generate Ninja depfile dependencies from the Bazel build graph to ensure that if
# anything changes in the Bazel build graph, Ninja will properly re-invoke Bazel
# if needed.
#
# - Legacy mechanism: use bazel_input_resource() or bazel_input_resource_directory().
#
# This mechanism exists for historical reason and is deprecated. It relies on a different
# pair of GN templates that also expose Ninja outputs to the Bazel build graph, with some
# rather important differences:
#
# - They use a different Bazel external namespace, named @legacy_ninja_build_outputs//
# to expose outputs.
#
# - They allow the exposition target to specify an arbitrary destination location
# for the Bazel filegroup() under @legacy_ninja_build_outputs//, which can lead
# to conflicts.
#
# For example:
#
# # //src/foo/BUILD.gn
# bazel_input_resource("foo_outputs") {
# deps = [ ":gen_foo" ]
# sources = get_target_outputs(":gen_foo")
# outputs = [ "foo_outputs" ]
# }
#
# Would expose the outputs as `@legacy_ninja_build_outputs//:foo_outputs` directly.
#
# - *every* bazel_input_resource() or bazel_input_resource_directory() *must* be
# reachable from the global list of labels
#
# - bazel_input_resource() and bazel_input_resource_directory() must be listed through
# the special `bazel_inputs` argument of bazel_action() targets.
#
#
#
# named @legacy_ninja_build_outputs.
#
# For example, to expose the files generated by an action `foo` as a
# filegroup() with Bazel label @legacy_ninja_build_outputs//:foo_files, one
# can use the following definition:
#
# ```gn
# # Expose all outputs generated by :foo in Bazel.
# bazel_input_resource("foo_files") {
# deps = [ ":foo" ]
# sources = get_target_outputs(":foo")
# outputs = [ "{{source_file_part}}" ]
# }
#
# IMPORTANT: Simply defining a bazel_input_xxx() target is NOT ENOUGH, it must
# ALSO be part of the transitive dependencies listed from one of the lists
# defined in //build/bazel/legacy_ninja_build_outputs.gni
#
# There is no way to enforce that with GN at the moment.
#
# Used internally by bazel_input_file() and bazel_input_directory()
template("_bazel_input_entry") {
_main_target_name = target_name
if (invoker.entry_type == "file") {
_output_files = rebase_path(invoker.outputs, root_build_dir)
} else if (invoker.entry_type == "directory") {
_output_dir = rebase_path(invoker.output_directory, root_build_dir)
} else {
assert(false, "Unknown _bazel_input_entry type: ${invoker.entry_type}")
}
# The Bazel package is the generator's GN directory, with an optional
# 'toolchain_<name>' prefix if it does not belong to the default toolchain.
# For example:
#
# generator = "//src/lib/foo"
# bazel_package = "src/lib/foo"
# bazel_name = "foo"
# final_label = "@gn_targets//src/lib/foo:foo"
#
# generator = "//zircon/tools/zbi(//build/toolchain:host_x64)
# bazel_package = "toolchain_host_x64/zircon/tools/zbi"
# bazel_name = "zbi"
# final_label = "@gn_targets//toolchain_host_x64/zircon/tools/zbi:zbi"
#
_bazel_package = get_label_info(invoker.generator, "dir")
_bazel_package = string_replace(_bazel_package, "//", "")
if (current_toolchain != default_toolchain) {
_toolchain_name = get_label_info(current_toolchain, "name")
_bazel_package = "toolchain_${_toolchain_name}/${_bazel_package}"
}
if (defined(invoker.gn_targets_name)) {
_bazel_name = invoker.gn_targets_name
} else {
_bazel_name = get_label_info(invoker.generator, "name")
}
group(_main_target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
deps = [ invoker.generator ]
metadata = {
# Used by generate_gn_targets_repository_manifest() template, which
# is part of the new scheme to expose Ninja outputs as Bazel inputs.
gn_targets_repository_entries = [
{
generator_label =
get_label_info(invoker.generator, "label_with_toolchain")
bazel_package = _bazel_package
bazel_name = _bazel_name
if (invoker.entry_type == "file") {
output_files = _output_files
} else if (invoker.entry_type == "directory") {
output_directory = _output_dir
}
},
]
gn_targets_repository_entries_barrier = []
}
}
}
# Expose a set of GN target output files to Bazel.
#
# Calling this template does not build anything, but the resulting
# target should be in the dependencies of any bazel_action() target
# that needs to access these files from the Bazel graph.
#
# They will be exposed through a single filegroup() defined as
# @gn_targets//{target_dir}:{generator_name} in the Bazel graph,
# where {target_dir} matches the directory of the current target,
# and {generator_name} is the name of the generator target (
# which could be defined in a different directory).
#
# For example:
#
# ```
# # From //src/lib/BUILD.gn
# bazel_input_file("foo.bazel_inputs") {
# generator = ":foo"
# }
# ```
#
# Will expose the outputs of the `//src/lib:foo` target in the Bazel
# filegroup named `@gn_targets/src/lib:foo`.
#
# It is possible to change the name of the Bazel filegroup by setting
# the `gn_targets_name` argument. For example:
#
# ```
# bazel_input_file("foo.bazel_inputs") {
# generator = ":foo"
# gn_targets_name = "foo_files"
# }
# ```
#
# Will create a filegroup() named `@gn_targets//src/lib:foo_files`
# instead.
#
# Note: only the filegroup name can be change, not its package which is
# hard-coded to @gn_targets//{target_dir}.
#
# If no 'outputs' argument is provided, *and* the generator and target
# are defined in the same BUILD.gn file and toolchain, then
# get_target_outputs(generator) will be used to expose all outputs
# from the generator target.
#
# If the generator and target are in different BUILD.gn file, or
# different toolchain contexts, the 'outputs' argument is required.
#
# When an 'outputs' argument is specified, it doesn't need to list all
# outputs from the generator, only those that need to be exposed.
#
# It is an error to expose a directory through 'outputs', as Bazel
# will complain when trying to access its content later. Use
# bazel_input_directory() to handle this use case.
#
# Arguments:
# generator: GN label of target that generates the output files.
# This can also be the label of a group() that depends on multiple
# generating targets. In this case, the 'outputs' argument will be
# required to list the output files from said dependencies to be
# exposed.
#
# outputs: Optional. List of output files for this target that will be exposed
# to Bazel. This argument is required if this target and the generator are
# defined in different directories or toolchains.
#
# gn_target_name: Optional. Name of Bazel filegroup() used to expose the
# output files. If not provided, this will use the name of the generator
# target.
#
# testonly, visibility: Usual GN meaning.
#
template("bazel_input_file") {
assert(defined(invoker.generator),
"bazel_input_file() requires a generator argument!")
# Auto-compute 'outputs' value if not provided, and the right conditions are checked.
if (!defined(invoker.outputs)) {
_target_dir = get_label_info(":$target_name", "dir")
_generator_dir = get_label_info(invoker.generator, "dir")
assert(
_target_dir == _generator_dir,
"bazel_input_file() requires an 'outputs' argument if target and generator are from different directories (${_target_dir} != ${_generator_dir}")
_target_toolchain = get_label_info(":$target_name", "toolchain")
_generator_toolchain = get_label_info(invoker.generator, "toolchain")
assert(
_target_toolchain == _generator_toolchain,
"bazel_input_file() requires an 'outputs' argument if target and generator are from different toolchains (${_target_toolchain} != ${_generator_toolchain}")
invoker.outputs = get_target_outputs(invoker.generator)
}
_bazel_input_entry(target_name) {
entry_type = "file"
forward_variables_from(invoker, "*")
}
}
# Expose a GN target output directory to Bazel.
#
# This is similar to bazel_input_file() but allows exposing an output
# directory, for the rare case where a GN target generates one.
#
# Note that only a single directory can be specified per instance.
# The directory will be exposed as a Bazel filegroup() with the
# name `@gn_targets//{gn_dir}:{gn_target}`. The filegroup's
# sources will be grabbed with a `glob()` statement and will thus
# contain all files and directories contained in it.
#
# Arguments:
# generator: GN label of target that generates the output files.
#
# output_directory: GN path to output directory populated by the generator.
# This argument can be omitted if all conditions apply:
# - The target and the generator are defined in the same BUILD.gn file.
# - The target and the generator are defined in the same GN toolchain context.
# - The generator only produces a single output (from GN's point of view).
#
# gn_targets_name: Optional. Name of Bazel filegroup() used to expose the
# output files. If not provided, this will use the name of the generator
# target.
#
# testonly, visibility: Usual GN meaning.
#
template("bazel_input_directory") {
assert(defined(invoker.generator),
"bazel_input_directory() requires a generator argument!")
if (!defined(invoker.output_directory)) {
assert(defined(invoker.generator),
"bazel_input_directory() requires a 'generator' argument")
_target_dir = get_label_info(":$target_name", "dir")
_generator_dir = get_label_info(invoker.generator, "dir")
assert(
_target_dir == _generator_dir,
"bazel_input_file() requires an 'outputs' argument if target and generator are from different directories (${_target_dir} != ${_generator_dir}")
_target_toolchain = get_label_info(":$target_name", "toolchain")
_generator_toolchain = get_label_info(invoker.generator, "toolchain")
assert(
_target_toolchain == _generator_toolchain,
"bazel_input_file() requires an 'outputs' argument if target and generator are from different toolchains (${_target_toolchain} != ${_generator_toolchain}")
_outputs = get_target_outputs(invoker.generator)
assert(
_outputs != [] && _outputs == [ _outputs[0] ],
"bazel_input_directory() requires an 'output_directory' argument if the generator produces more than one output: ${_outputs}")
invoker.output_directory = _outputs[0]
}
assert(defined(invoker.output_directory),
"Missing output_directory argument.")
assert("${invoker.output_directory}" == invoker.output_directory,
"output_directory argument must be a path string.")
_bazel_input_entry(target_name) {
entry_type = "directory"
forward_variables_from(invoker, "*")
}
}
# DEPRECATED: Use bazel_input_file() instead!
#
# Expose a set of Ninja output files as a corresponding Bazel filegroup()
# of prebuilt input sources for the Bazel build.
#
# This template works like copy() or resource().
#
# ```gn
# # Expose all outputs generated by :foo in Bazel.
# bazel_input_resource("foo_files") {
# deps = [ ":foo" ]
# sources = get_target_outputs(":foo")
# outputs = [ "{{source_file_part}}" ]
# }
#
# ...
#
# Make sure this is reachable from the transitive dependencies listed in
# //build/bazel/legacy_ninja_build_outputs.gni, e.g.:
#
# ```
# gn_labels_for_bazel_inputs += [ "//src/foo:foo_files" ]
# ```
#
# Assuming that :foo generates the following files:
#
# out/default/gen/src/foo/foo.h
# out/default/gen/src/foo/foo.cc
#
# Then this will generate something like that @legacy_ninja_build_outputs/BUILD.bazel:
#
# ```bazel
# filegroup("foo_files") {
# srcs = [
# "foo.h",
# "foo.cc",
# ]
# )
# ```
#
# After creating the symlinks as:
#
# $BAZEL_TOPDIR/output_base/external/legacy_ninja_build_outputs/
# foo.h --> ../../../../../src/foo/foo.h
# foo.cc --> ../../../../../src/foo/foo.cc
#
# Arguments:
# name: (optional)
# Bazel filegroup name for the set of files covered by this target.
# If not specified, defaults to target_name. Note that the filegroup()
# will be part of the top-level BUILD.bazel file generated by the
# build)_inputs_workspace() dependent. This name cannot contain a
# directory separator or colon.
# Type: string
#
# sources
# Required: List of output files that become sources in the Bazel
# workspace. Technically works with Ninja source files as well, but these
# are already exposed to Bazel by default, and don't need to be
# listed in a bazel_input_resource() target. See copy() for details.
# Type: list(file)
#
# outputs
# Required: List of one runtime path. This must be a relative path (no
# leading `/`). It can use placeholders based on $sources; see copy()
# and `gn help source_expansion`.
# Type: list(path)
#
# deps
# Optional: Targets that produce $sources. Any files listed in
# $sources that are produced by the build should be produced by a
# target listed here.
# Type: list(label)
#
# gn_targets_name
# Optional: Name of the filegroup target that will be defined in the
# @gn_targets repository for this set of files. Default is target_name
# with any "_bazel_inputs" suffix removed.
# Type: string
#
template("bazel_input_resource") {
_name = target_name
if (defined(invoker.name)) {
_name = invoker.name
assert(string_replace(_name, "/", "") == _name,
"name cannot contain directory separators: $_name")
assert(string_replace(_name, ":", "") == _name,
"name cannot contain colon: $_name")
}
_sources = rebase_path(invoker.sources, root_build_dir)
_dest = process_file_template(invoker.sources, invoker.outputs)
foreach(dst_path, _dest) {
assert(
rebase_path(dst_path, "//") != dst_path,
"`outputs` in bazel_input_resource() cannot start with /: ${dst_path}")
}
_gn_label = get_label_info(":$target_name", "label_with_toolchain")
# _generator_target is not empty if there is a single dependency that
# defines the outputs.
_generator_target = ""
if (defined(invoker.deps)) {
_deps = invoker.deps
if (_deps != [] && _deps == [ _deps[0] ]) {
_generator_target = _deps[0]
_gn_targets_package = get_label_info(_generator_target, "dir")
_gn_targets_package = string_replace(_gn_targets_package, "//", "")
if (current_toolchain != default_toolchain) {
_toolchain_name = get_label_info(current_toolchain, "name")
_gn_targets_package =
"toolchain_${_toolchain_name}/${_gn_targets_package}"
}
}
}
# NOTE: Unlike bazel_input_file(), the default target name is the name
# of the bazel_input_resource() target, not the name of the generator,
# with an optional `_bazel_inputs` suffix removed.
if (defined(invoker.gn_targets_name)) {
_gn_targets_name = invoker.gn_targets_name
} else {
_gn_targets_name = target_name
}
# Remove optional '_bazel_inputs" suffix.
_gn_targets_name_no_suffix =
string_replace("${_gn_targets_name}##", "_bazel_inputs##", "##")
if (_gn_targets_name_no_suffix != "${_gn_targets_name}##") {
_gn_targets_name = string_replace(_gn_targets_name_no_suffix, "##", "")
}
group(target_name) {
forward_variables_from(invoker,
"*",
[
"metadata",
"name",
"outputs",
"sources",
])
metadata = {
# Used by bazel_inputs_manifest() template.
# See its documentation for the metadata schema.
bazel_inputs = [
{
name = _name
sources = _sources
destinations = _dest
gn_label = _gn_label
gn_targets_name = _gn_targets_name
},
]
bazel_inputs_barrier = []
if (_generator_target != "") {
# Used by generate_gn_targets_repository_manifest(), this makes
# bazel_input_resource() behave like bazel_input_file()
gn_targets_repository_entries = [
{
generator_label =
get_label_info(_generator_target, "label_no_toolchain")
bazel_name = _gn_targets_name
bazel_package = _gn_targets_package
output_files = rebase_path(invoker.sources, root_build_dir)
},
]
}
gn_targets_repository_entries_barrier = []
}
}
}
# DEPRECATED: Use bazel_input_directory() instead.
#
# bazel_input_resource_directory() is used to expose the content of a Ninja
# output directory as a Bazel input filegroup. Instead of passing a list of
# source files, `source_root` source point to a directory whose content will
# be symlinks into a bazel_build_inputs_workspace().
#
# IMPORTANT: This is not hermetic, and can lead to incorrect results during
# incremental builds, unless the directory's content is always cleared
# before the Ninja action that generates its content is run.
#
# For example:
#
# bazel_input_resource_directory"my-generated-resources") {
# source_dir = get_label_info(":resource-generator", "target_gen_dir")
# dest_dir = "data/resources"
# deps = [ ¨:resource-generator" ]
# }
#
# Parameters
# name: (optional)
# Bazel filegroup name for the set of files covered by this target.
# If not specified, defaults to target_name. Note that the filegroup()
# will be part of the top-level BUILD.bazel file generated by the
# build)_inputs_workspace() dependent. This name cannot contain a
# directory separator or colon.
# Type: string
#
# source_dir
# Required: GN path to the source directory that contains all outputs
# files to be exposed as a Bazel filegroup().
# Type: string(path)
#
# dest_dir
# Required: Destination path where all sources are exposed.
# Cannot start with a "/". Use an empty string to expose files directly
# to the workspace's top-level directory.
# Type: string(path)
#
# deps
# Optional: Targets that produce $sources. Any files listed in
# $sources that are produced by the build should be produced by a
# target listed here.
# Type: list(label)
#
# gn_targets_name
# Optional: Name of the filegroup target that will be defined in the
# @gn_targets repository for this set of files. Default is target_name
# with any "_bazel_inputs" suffix removed.
# Type: string
#
template("bazel_input_resource_directory") {
_name = target_name
if (defined(invoker.name)) {
_name = invoker.name
assert(string_replace(_name, "/", "") == _name,
"name cannot contain directory separators: $_name")
assert(string_replace(_name, ":", "") == _name,
"name cannot contain colon: $_name")
}
assert(defined(invoker.dest_dir), "dest_dir is required")
dest_dir = invoker.dest_dir
if (dest_dir != "") {
assert(rebase_path(dest_dir, "foo") != dest_dir,
"dest_dir cannot start with /: $dest_dir")
assert(dest_dir != "." && dest_dir != ".." &&
string_replace(dest_dir, "./", "") == dest_dir,
"dest_dir cannot contain . or .. path elements: $dest_dir")
# Add trailing directory separator.
dest_dir = string_replace(dest_dir + "//", "//", "/")
}
_generator_target = ""
if (defined(invoker.deps)) {
_deps = invoker.deps
if (_deps != [] && _deps == [ _deps[0] ]) {
_generator_target = get_label_info(_deps[0], "label_no_toolchain")
_gn_targets_package = get_label_info(_generator_target, "dir")
_gn_targets_package = string_replace(_gn_targets_package, "//", "")
if (current_toolchain != default_toolchain) {
_toolchain_name = get_label_info(current_toolchain, "name")
_gn_targets_package =
"toolchain_${_toolchain_name}/${_gn_targets_package}"
}
}
}
# NOTE: Unlike bazel_input_directory(), the default target name is the name
# of the bazel_input_resource_directory() target, not the name of the generator,
# with an optional `_bazel_inputs` suffix removed.
if (defined(invoker.gn_targets_name)) {
_gn_targets_name = invoker.gn_targets_name
} else {
_gn_targets_name = target_name
}
# Remove optional '_bazel_inputs" suffix.
_gn_targets_name_no_suffix =
string_replace("${_gn_targets_name}##", "_bazel_inputs##", "##")
if (_gn_targets_name_no_suffix != "${_gn_targets_name}##") {
_gn_targets_name = string_replace(_gn_targets_name_no_suffix, "##", "")
}
group(target_name) {
forward_variables_from(invoker,
[
"deps",
"testonly",
"visibility",
])
metadata = {
# Used by bazel_inputs_manifest() template.
bazel_inputs = [
{
name = _name
source_dir = rebase_path(invoker.source_dir, root_build_dir)
dest_dir = dest_dir
gn_label = get_label_info(":$target_name", "label_with_toolchain")
gn_targets_name = _gn_targets_name
},
]
bazel_inputs_barrier = []
if (_generator_target != "") {
# Used by generate_gn_targets_repository_manifest(), this makes
# bazel_input_resource_directory() behave like bazel_input_directory()
gn_targets_repository_entries = [
{
generator_label =
get_label_info(_generator_target, "label_with_toolchain")
bazel_package = _gn_targets_package
bazel_name = _gn_targets_name
output_directory = rebase_path(invoker.source_dir, root_build_dir)
},
]
}
gn_targets_repository_entries_barrier = []
}
}
}
# Generate a manifest file describing the content of the Bazel inputs
# repository that will be used by the Bazel workspace to read Ninja outputs
# as sources / prebuilts.
#
# Args:
# output:
# Path to generated manifest file.
#
# inputs_deps:
# A list of targets, all transitive dependencies which are bazel_input_xxx()
# target will generate one entry in the manifest.
#
template("generate_bazel_inputs_manifest") {
# Generate a single manifest file that collects all bazel_input_xxx()
# resources. Each metadata entry is a scope that describes a single
# Bazel filegroup() target that will appear at the top of the
# auto-generated workspace.
#
# There are two types of entries:
#
# ## REGULAR ENTRIES
#
# These entries expose an explicit list of files, they look like:
#
# name: (required)
# Bazel filegroup name.
# Type: string
#
# destinations: (required)
# List of input files, relative to the top of the generated workspace.
# Each one will appear in the `srcs` list of the corresponding
# filegroup.
#
# sources: (required)
# List of source files for the filegroup. Must have the same
# size as the `destinations` list.
# Type: list of paths relative to the root_build_dir
#
# gn_label:
# GN label of target that defines this entry.
# Type: GN label string
#
# They should generate Bazel targets that look like:
#
# filegroup(
# name = "<name>",
# srcs = [
# <destination_1>,
# <destination_2>,
# ...
# ],
# )
#
# Where <destination_N> is the N-th entry in `destinations`, and will be
# the path to a symlink (in the repository) to the corresponding
# <sources_N> file.
#
# ## DIRECTORY ENTRIES
#
# These entries expose all files under a given output directory as
# a single filegroup() using the glob() function. IMPORTANT: For
# correctness, only use these when it is 100% sure that the content
# of the source directory is re-created properly during incremental
# builds. These look like:
#
# name: (required)
# Bazel filegroup name.
# Type: string
#
# source_dir: (required)
# A source directory path, relative to the Ninja build output
# directory, which will contain all input files for the Bazel
# filegroup().
#
# dest_dir: (required)
# A directory prefix for all input files, relative to the top of
# the generated workspace. This will be a symlink to source_dir,
# and the filegroup() will use a glob(["<dest_dir>/*"]) call to get all
# files in it.
#
# gn_label: (optional)
# GN label of target that defines this entry.
# Type: GN label string
#
# They should generate Bazel targets that look like:
#
# filegroup(
# name = "<name>",
# srcs = glob(["<dest_dir>/**]),
# )
#
# Where <dest_dir> is a repository symlink that points to source_dir.
#
generated_file(target_name) {
forward_variables_from(invoker, [ "testonly" ])
outputs = [ invoker.output ]
data_keys = [ "bazel_inputs" ]
walk_keys = [ "bazel_inputs_barrier" ]
deps = invoker.inputs_deps
output_conversion = "json"
}
}
# Generate a manifest file describing the content of the @gn_targets
# repository. Only used internally by the Fuchsia platform build.
# This should not be invoked by regular BUILD.gn files.
#
# Arguments:
# deps: List of root dependencies to walk from to collect all metadata.
# output: Output file path. Defaults to $target_gen_dir/$target_name.json
#
template("generate_gn_targets_repository_manifest") {
if (defined(invoker.output)) {
_output = invoker.output
} else {
_output = "$target_gen_dir/$target_name.json"
}
# There are two types of entries:
#
# ## REGULAR ENTRIES
#
# These entries expose an explicit list of files, as a single file group,
# they look like:
#
# bazel_name: (required)
# Bazel filegroup name.
# Type: Bazel target name string
#
# bazel_package: (required)
# Bazel package name (without leading // prefix).
# Type: Bazel label string
#
# generator_label: (required)
# GN target label that generates the file, must include toolchain.
# Type: GN label string
#
# output_files: (required)
# List of Ninja build artifacts, relative to the Ninja build directories.
# These will appear in the 'srcs' attribute of the filegroup.
# Type: list of paths relative to the root_build_dir
#
# They should generate Bazel targets in @gn_targets//<bazel_package>/BUILD.bazel
# that look like:
#
# # From <generator_label>
# filegroup(
# name = "<bazel_name>",
# srcs = [
# "_files/<output_file_1>",
# "_files/<output_file_2>",
# ...
# ],
# )
#
# Where <output_file_N> is the N-th entry in `output_files`, and will be
# the path to a symlink (in the repository) into the special @gn_targets//_files
# package.
#
# ## DIRECTORY ENTRIES
#
# These entries expose all files under a given Ninja output directory as
# a single filegroup() using the glob() function. IMPORTANT: For
# correctness, only use these when it is 100% sure that the content
# of the source directory is re-created properly during incremental
# builds. These look like:
#
# bazel_name: (required)
# Bazel filegroup name.
# Type: Bazel target name string
#
# bazel_package: (required)
# Bazel package name (without leading // prefix).
# Type: Bazel label string
#
# generator_label: (required)
# GN target label that generates the file, must include toolchain.
# Type: GN label string
#
# output_directory: (required)
# Path to the directory containing Ninja output files, relative to the Ninja build directories.
# Type: directory path relative to the root_build_dir
#
# They should generate Bazel targets in @gn_targets//<bazel_package>/BUILD.bazel
# that look like:
#
# # From <generator_label>
# filegroup(
# name = "<bazel_name>",
# srcs = glob(["_files/<output_directory>/**]),
# )
#
generated_file(target_name) {
forward_variables_from(invoker, [ "testonly" ])
outputs = [ _output ]
data_keys = [ "gn_targets_repository_entries" ]
walk_keys = [ "gn_targets_repository_entries_barrier" ]
deps = invoker.deps
output_conversion = "json"
}
}