blob: 8df69238026fea8172d216035114831e7192e20a [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/config/profile/config.gni")
import("//build/rust/config.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_type
# Usually GN handles this internally for rust targets, but we have to set it explicitly
# for targets that generate a corresponding auxiliary target so that clippy and rustdoc have
# access to it. See https://doc.rust-lang.org/reference/linkage.html for possible values
#
# 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"'
#
# check_cfgs (optional)
# A list of valid configurations for the target.
# Passed to rustc as '--check-cfg=cfg(###)'.
# Not specifying or using an empty list disables configuration checking.
# See https://doc.rust-lang.org/nightly/rustc/check-cfg.html for the syntax.
#
# 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)
#
# pass_through
# A scope of arguments to pass directly to the underlying wrapped target.
# Only the primary target generated will receive these arguments.
#
# disable_rbe (optional)
# Set to true to force this target to build locally, overriding the global
# `rust_rbe_enable`.
#
# link_args (optional)
# List of arguments to pass to the linker via "-Clink-args=...".
#
# disable_clippy (optional)
# Don't run clippy on this target.
#
# emit_tool_path (optional)
# Exclude this target from tool_paths.json.
#
# quiet_clippy (boolean, optional)
# Run clippy on this target, producing a JSON output but do not print the output or fail the
# target based on clippy's success. Intended for use when testing clippy itself, use in normal
# build targets will hide lint warnings from developers and tools while still paying the
# overhead of running clippy.
#
# 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.
#
#
# all_dependent_configs
# applicable_licenses
# assert_no_deps
# configs
# data_deps
# deps
# inputs
# metadata
# public_configs
# public_deps
# sources
# testonly
# visibility
# The usual GN meaning.
template("rustc_artifact") {
if (current_toolchain == shlib_toolchain) {
# For Rust targets that are expanded in the shared toolchain, redirect to the
# base toolchain with variant. See https://fxbug.dev/387208039.
group(target_name) {
forward_variables_from(invoker,
[
"all_dependent_configs",
"applicable_licenses",
"assert_no_deps",
"testonly",
"visibility",
])
public_deps = [ ":${target_name}(${variant_base_toolchain})" ]
not_needed(invoker, "*")
}
} else {
_remote_inputs = []
if (defined(invoker.inputs)) {
_remote_inputs = invoker.inputs
}
_local_inputs = _remote_inputs
# Compute the metadata used to uniquely identify this target within rustc.
# In particular, it is used as a key in the incremental cache to prevent
# builds of the same crate name from clobbering each others' cache entries.
# It is also used in symbol mangling.
#
# This is a space-separated list.
_codegen_metadata =
rebase_path(target_out_dir, root_build_dir) + " " + target_name
_rustflags = [ "-Cmetadata=${_codegen_metadata}" ]
_flag_deps = [ "//build/rust:api_level_cfg_flags" ]
_flag_inputs = [ "${root_out_dir}/rust_api_level_cfg_flags.txt" ]
_rustflags += [ "@rust_api_level_cfg_flags.txt" ]
if (defined(invoker.features)) {
foreach(i, invoker.features) {
_rustflags += [ "--cfg=feature=\"${i}\"" ]
}
}
if (defined(invoker.check_cfgs)) {
foreach(i, invoker.check_cfgs) {
_rustflags += [ "--check-cfg=cfg(${i})" ]
}
}
if (defined(invoker.rustflags)) {
_rustflags += invoker.rustflags
}
_group_name = target_name
_actual_target_name = "${target_name}.actual"
_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
}
# These do not have aux targets (yet).
_should_define_rust_aux = invoker.crate_type != "cdylib" &&
(invoker.crate_type != "proc-macro" ||
current_toolchain == toolchain_variant.base)
if (_should_define_rust_aux) {
# See //build/rust/rust_auxiliary.gni for more info about .aux targets. We
# depend on this specific name (without the .actual suffix), so declare it
# here.
_aux_target_name = "${target_name}.aux"
if (defined(invoker.rust_auxiliary_name)) {
_aux_target_name = invoker.rust_auxiliary_name
}
rust_auxiliary(_aux_target_name) {
forward_variables_from(invoker,
[
"actual_name",
"aliased_deps",
"configs",
"crate_root",
"crate_type",
"define_rustdoc_test_override",
"disable_clippy",
"disable_rustdoc",
"include_rustdoc_first_party",
"original_target_name",
"quiet_clippy",
"quiet_rustdoc",
"rustdoc_args",
"rustdoc_out_dir",
"rustenv",
"sources",
"testonly",
"visibility",
"rustdoc_parts_dir",
"zip_rustdoc_to",
])
crate_name = string_replace(invoker.crate_name, "-", "_")
if (!defined(actual_name)) {
actual_name = _group_name
}
invoker_deps = invoker.deps
rustflags = _rustflags
if (!defined(configs)) {
configs = []
}
configs += [ "//build/config/rust:edition_${invoker.edition}" ]
# Add the global lint defaults.
configs += [ "//build/config/rust/lints:clippy_warn_default" ]
# Add production-oriented lints to non-test code.
if (!(defined(testonly) && testonly)) {
configs += [ "//build/config/rust/lints:clippy_warn_production" ]
}
# rustdoc should not be data_dep'd for third party crates
include_rustdoc_first_party = true
# We should only generate clippy lints for first party crates,
# as lints for third party crates aren't actionable
enable_clippy_first_party =
!defined(invoker.disable_clippy) || !invoker.disable_clippy
if (crate_type == "bin") {
# search index size, mostly.
disable_rustdoc_binary = true
}
if (crate_type == "rlib" || crate_type == "proc-macro") {
if (defined(invoker.output_dir)) {
searchdir_path = invoker.output_dir
} else {
searchdir_path =
get_label_info(":${_actual_target_name}", "target_out_dir")
if (rust_one_rlib_per_dir) {
searchdir_path += "/" + _actual_target_name
}
}
_output_name = invoker.crate_name
if (defined(invoker.output_name)) {
_output_name = invoker.output_name
}
rlib_path = "${searchdir_path}/lib${_output_name}.rlib"
}
}
} else {
not_needed(invoker,
[
"original_target_name",
"disable_clippy",
])
}
# Every first party Rust target is actually a group of both target_name.actual
# and target_name.aux.
# There is a group here, and in rust_auxiliary.gni. This group exists so that
# rustdoc and clippy targets can be built in parallel with the actual target.
group(_group_name) {
forward_variables_from(invoker,
[
"applicable_licenses",
"testonly",
"visibility",
])
public_deps = [ ":${_actual_target_name}" ]
if (_should_define_rust_aux) {
public_deps += [ ":${_aux_target_name}" ]
}
metadata = {
test_component_manifest_program_barrier = [ ":${_actual_target_name}" ]
link_output_barrier = [ ":${_actual_target_name}" ]
# Only include the actual target in the compilation deps metadata
rust_compilation_deps_barrier = [ ":${_actual_target_name}" ]
}
}
# Forwards to: rust_library, rust_proc_macro, executable, shared_library,
# or static_library in //build/config/BUILDCONFIG.gn.
target(invoker.target_type, _actual_target_name) {
forward_variables_from(invoker,
[
"aliased_deps",
"all_dependent_configs",
"applicable_licenses",
"assert_no_deps",
"crate_type",
"data_deps",
"deps",
"emit_tool_path",
"exclude_toolchain_tags",
"metadata",
"output_dir",
"output_extension",
"output_name",
"output_prefix_override",
"pool",
"public_configs",
"public_deps",
"runtime_deps",
"rustenv",
"testonly",
"variant_selector_target_type",
"visibility",
])
# rustc does not support dashes in crate names.
crate_name = string_replace(invoker.crate_name, "-", "_")
crate_root = invoker.crate_root
rustflags = _rustflags
if (rust_rbe_enable) {
rustflags += [ "--remote-flag=--label='" +
get_label_info(":${_actual_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)) ]
}
configs = []
if (defined(invoker.configs)) {
configs = invoker.configs
}
configs += [ "//build/config/rust:edition_${invoker.edition}" ]
inputs = _local_inputs + _flag_inputs
# When building with profile data, add the profile path to
# the inputs to conform with the input verifier.
if (pgo_profile_path != "") {
inputs += [ pgo_profile_path ]
}
deps += _flag_deps
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" ]
}
if (defined(invoker.link_args)) {
foreach(link_arg, invoker.link_args) {
rustflags += [ "-Clink-args=" + link_arg ]
}
}
# The Fuchsia standard library has an implicit #[link] directive
# pointing to libfdio.so
if (is_fuchsia && (invoker.target_type == "executable" ||
invoker.target_type == "shared_library" ||
invoker.target_type == "loadable_module")) {
deps += [ "//src/lib/fdio/rust:fdio_for_rust_stdlib" ]
}
if (defined(visibility)) {
visibility += [ ":${_group_name}" ]
}
}
}
}