blob: bfb1e19b549cd79cfd92f4ddc004bebc61ed3e03 [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.
import("//build/rust/clippy.gni")
import("//build/toolchain/rbe.gni")
# Common logic for implementing the other rustc_* templates in this directory.
# Should not be called directly outside of //build/rust.
#
# Parameters
#
# target_type
# Name of the template or rule to wrap, as a string.
#
# crate_name
# Name of the crate as passed to rustc. All dashes will be replaced
# with underscores in the crate name: <name_underscored>
#
# crate_root
# Location of the crate root (e.g. `src/main.rs` or `src/lib.rs`).
#
# edition
# Edition of the Rust language to be used. See
# https://doc.rust-lang.org/edition-guide/editions/index.html for more info on rust editions.
#
# enforce_source_listing (optional)
# When true, enforces that any source files used by the Rust compiler are
# listed in `sources`. Defaults to true.
#
# sources (optional)
# List of source files which this crate is allowed to compile. Only
# allowed when `enforce_source_listing = true`.
# The Rust compiler discovers source files by following `mod` declarations
# starting at the `source_root`. The discovered source files must match this
# list.
#
# rustflags
# Extra rust compiler flags passed directly to rustc.
#
# features (optional)
# A list of conditional compilation flags to enable. This can be used to set features for crates
# built in-tree which are also published to crates.io. This would be passed to rustc as
# '--cfg feature="XXX"'
#
# rustenv (optional)
# A list of environment variables that will be set when running the rust
# compiler. These can be accessed at compile time with
# [`std::env!`](https://doc.rust-lang.org/stable/std/macro.env.html)
#
# configs (optional)
# A list of config labels applying to this target.
#
# deps
# List of GN targets on which this crate depends.
#
# pass_through
# A scope of arguments to pass directly to the underlying wrapped target.
# Only the primary target generated will receive these arguments.
#
# metadata (optional)
# Metadata to apply to the primary wrapped target.
#
# inputs (optional)
# List of additional non-source files read by the compiler. These are typically
# configuration or test-data files included in the build with the `include_str!`
# macro.
#
# sources
# List of source files which this crate is allowed to compile.
# The Rust compiler discovers source files by following `mod` declarations
# starting at the `crate_root`. The discovered source files must match this
# list.
#
# disable_rbe (optional)
# Set to true to force this target to build locally, overriding the global
# `rust_rbe_enable`.
#
# disable_clippy (optional)
# Don't run clippy on this target.
#
# clippy_crate_type
# Usually GN handles this internally for rust targets, but we have to set it explicitly
# for targets that generate a corresponding clippy target so that clippy has access to it.
# See https://doc.rust-lang.org/reference/linkage.html for possible values
#
# original_target_name
# The name of the target as it appears in the BUILD file. Enables tooling
# to find the template invocation in a BUILD file where this target was defined.
#
# testonly (optional)
# Standard GN meaning. Testonly option for the generated targets.
#
# visibility (optional)
# Standard GN meaning. The visibility option for the generated targets.
#
template("rustc_artifact") {
# rustc does not support dashes in crate names
_crate_name = string_replace(invoker.crate_name, "-", "_")
_crate_root = invoker.crate_root
_remote_inputs = []
if (defined(invoker.inputs)) {
_remote_inputs = invoker.inputs
}
_local_inputs = _remote_inputs
# enable these features for the target
_rustflags = []
if (defined(invoker.features)) {
foreach(i, invoker.features) {
_rustflags += [ "--cfg=feature=\"${i}\"" ]
}
}
if (defined(invoker.rustflags)) {
_rustflags += invoker.rustflags
}
assert(
defined(invoker.edition),
"Rust targets must set an edition. For new rust targets use: `edition = \"2021\"`")
_configs = invoker.configs
_edition = invoker.edition
_configs += [ "//build/config/rust:edition_${_edition}" ]
_target_name = "$target_name.actual"
_clippy_name = "$target_name.clippy"
_disable_clippy = defined(invoker.disable_clippy) && invoker.disable_clippy
if (!_disable_clippy) {
clippy(_clippy_name) {
forward_variables_from(invoker,
[
"testonly",
"rustenv",
])
clippy_crate_type = invoker.clippy_crate_type
configs = _configs
crate_root = _crate_root
deps = invoker.deps
rustflags = _rustflags
sources = invoker.sources
}
} else {
if (defined(invoker.clippy_crate_type)) {
not_needed(invoker, [ "clippy_crate_type" ])
}
if (defined(invoker.rustenv)) {
not_needed(invoker, [ "rustenv" ])
}
not_needed([ "_clippy_name" ])
}
_use_rbe = rust_rbe_enable
if (defined(invoker.disable_rbe) && invoker.disable_rbe) {
_use_rbe = false
}
if (rust_rbe_enable && !_use_rbe) {
# Disable RBE for this target through a fake rustflag,
# that is intercepted by rustc-remote-wrapper.sh.
_rustflags += [ "--remote-disable" ]
}
if (_use_rbe) {
# Depend on Rust/RBE scripts and tools
_local_inputs += rust_rbe_deps
}
# Every rust target is actually a group of both target_name.actual and
# optionally target_name.clippy (if include_clippy is set)
group(target_name) {
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
public_deps = [ ":$_target_name" ]
metadata = {
test_component_manifest_program_barrier = [ ":$_target_name" ]
link_output_barrier = [ ":$_target_name" ]
}
if (!_disable_clippy) {
_outputs = get_target_outputs(":$_clippy_name")
_original = get_label_info(":${invoker.original_target_name}",
"label_with_toolchain")
metadata.rust_source_map = [
{
clippy = get_label_info(":$_clippy_name", "label_with_toolchain")
original = _original
output = rebase_path(_outputs[0], root_build_dir)
src = []
foreach(s, invoker.sources) {
src += [ rebase_path(s, root_build_dir) ]
}
},
]
if (include_clippy) {
data_deps = [ ":$_clippy_name" ]
}
} else {
not_needed(invoker, [ "original_target_name" ])
}
}
target(invoker.target_type, _target_name) {
crate_root = _crate_root
crate_name = _crate_name
rustflags = []
if (rust_rbe_enable) {
rustflags +=
[ "--remote-flag=--label='" +
get_label_info(":$_target_name", "label_with_toolchain") + "'" ]
}
if (_use_rbe && _remote_inputs != []) {
# Signal to rustc-remote-wrapper.sh that there are additional
# inputs to upload. This flag is stripped away from the eventual
# rustc command.
rustflags += [
"--remote-inputs",
string_join(",", rebase_path(_remote_inputs, root_build_dir)),
]
}
rustflags += _rustflags
configs = []
configs = _configs
deps = invoker.deps
inputs = _local_inputs
if (!defined(invoker.enforce_source_listing) ||
invoker.enforce_source_listing) {
# fail early when the user forgets to list sources
assert(defined(invoker.sources), "sources must be listed")
sources = invoker.sources
} else {
not_needed(invoker, [ "sources" ])
# This is a hack to workaround the fact that a GN `tool` invocation can't receive arbitrary input.
# Add a sentinel value so that enforcement is skipped.
sources = [ "//build/rust/__SKIP_ENFORCEMENT__.rs" ]
# Opting out of strict sources check requires that the package is present
# in a global allow-list.
deps += [ "//build/rust:disable_strict_sources_check_allowlist" ]
}
rustenv = []
if (defined(invoker.rustenv)) {
rustenv += invoker.rustenv
}
# Clippy target is a gen dep if it's not included in the group
if (!_disable_clippy && !include_clippy) {
gen_deps = [ ":$_clippy_name" ]
}
# _pass_through and not_needed are to workaround https://crbug.com/gn/10
_pass_through = invoker.pass_through
assert(!defined(_pass_through.metadata))
not_needed([ "_pass_through" ])
metadata = {
if (defined(invoker.metadata)) {
forward_variables_from(invoker.metadata, "*")
}
}
# pass through these variables unmodified
forward_variables_from(invoker.pass_through, "*")
forward_variables_from(invoker,
[
"testonly",
"visibility",
])
}
}