blob: 204cc35f1a5901df8e3ab3a554513aa491ff5e67 [file] [log] [blame]
# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/rust/rust_target.gni")
# Defines a Rust static library which can be used by downstream Rust or C++
# targets. This is a single Rust compilation unit consisting of potentially
# multiple .rs files.
#
# We term this 'rust_static_library' because it is used most analogously
# to a C++ 'static_library' in Chromium. Like the C++ one, it can be compiled
# independently into an intermediate linking target. The output contains the
# object file(s) of the GN target's sources, and not its dependencies.
#
# Parameters
#
# sources
# List of source files which this crate is allowed to compile, which is
# used to determine the impact of source code changes on other GN targets.
# This is not used by the Rust compiler, as it discovers source files by
# following `mod` declarations starting at the `crate_root`. The
# discovered source files must match this list. (This is not yet enforced,
# but will be.)
#
# edition (optional)
# Edition of the Rust language to be used.
# Options are "2015", "2018" and "2021". Defaults to "2021".
#
# allow_unsafe (optional)
# Set to true to allow unsafe code in this target. Defaults to false.
#
# configs (optional)
# A list of config labels (in the GN meaning) applying to this target.
#
# rustflags (optional)
# Explicit flags for rustc command line. (Use 'edition' or 'features'
# where possible).
#
# deps (optional)
# List of GN targets on which this crate depends. These may be Rust
# or non-Rust targets.
#
# public_deps (optional)
# List of GN targets on which this crate depends, and which are exported
# into the dependency list of any crate that depends on it. Dependency
# crates that appear in the public API should be included here.
#
# test_deps (optional)
# List of GN targets on which this crate's tests depend, in addition
# to deps.
#
# is_gtest_unittests (optional)
# Should only be set to true for rlibs of gtest unit tests. This ensures
# all objects in the rlib are linked into the final target, rather than
# pruning dead code, so that the tests themselves are not discarded by the
# linker.
#
# mutually_dependent_target (optional)
# mutually_dependent_public_deps (optional)
# These is for use by the mixed_target() template.
#
# If this Rust code is intrinsically paired with some C/C++ code,
# with bidirectional calls between the two, then this would
# be a circular dependency. GN does not allow circular dependencies,
# (other than for header files per allow_circular_includes_from).
# But this is common for a 'component' which has both Rust and C++
# code. You should structure things such that the C++ code depends
# on the Rust code in the normal way:
# static_library("cpp_stuff") {
# deps = [ "rust_stuff" ]
# # ..
# }
# but that the Rust target also notes the C++ target using this
# 'mutually_dependent_target' parameter.
# rust_static_library("rust_stuff") {
# mutually_dependent_target = "cpp_stuff"
# mutually_dependent_public_deps = _cpp_stuff_public_deps
# # ..
# }
#
# This causes the Rust unit tests, if generated, to depend on the mutually
# dependent target, since depending on the Rust code only would be
# insufficient. And it allows any C++ bindings generated from the Rust code
# to include headers from the mutually_dependent_target by depending on its
# public_deps.
#
# build_native_rust_unit_tests (optional)
# Builds native unit tests (under #[cfg(test)]) written inside the Rust
# crate. This will create a `<name>_unittests` executable in the output
# directory when set to true.
#
# unit_test_target (optional)
# Overrides the default name for the unit tests target
#
# crate_root (optional)
# Location of the crate root.
# This defaults to `./src/lib.rs` and should only be changed when
# absolutely necessary (such as in the case of generated code).
#
# 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. Each feature in the list will be passed to rustc as
# '--cfg feature=XXX'
#
# cxx_bindings (optional)
# A list of Rust files which contain #[cxx::bridge] mods and should
# therefore have C++ bindings generated. See https://cxx.rs.
# This will automatically add appropriate dependencies: there's no
# need to depend on the cxx crate or any generated bindings.
#
# visibility (optional)
# rustflags (optional)
# crate_name (optional)
# Per the usual gn meaning for Rust targets.
#
# inputs (optional)
# Additional input files needed for compilation (such as `include!`ed files)
#
# test_inputs (optional)
# Same as above but for the unit tests target
#
# rustc_metadata (optional)
# Override the metadata identifying the target's version. This allows e.g.
# linking otherwise conflicting versions of the same Rust library. The
# metadata string will also be appended to the output library names.
# Should be used sparingly, since generally we should have one version and
# build of each target.
#
# Example of usage:
#
# rust_static_library("foo_bar") {
# deps = [
# "//boo/public/rust/bar",
# "//third_party/rust/crates:argh",
# "//third_party/rust/crates:serde",
# "//third_party/rust/crates:slab",
# ]
# sources = [ "src/lib.rs" ]
# }
#
# This template is intended to serve the same purpose as 'rustc_library'
# in Fuchsia.
template("rust_static_library") {
_target_name = target_name
_configs = []
_all_dependent_configs = []
if (defined(invoker.configs)) {
_configs += invoker.configs
}
# TODO(dcheng): Is there any value in allowing rust_shared_library() to also
# set `is_gtest_unittest` to true?
if (defined(invoker.is_gtest_unittests) && invoker.is_gtest_unittests) {
config("${_target_name}_alwayslink") {
# Targets using the #[gtest(...)] proc macro register their tests with
# static initializers. A rust library target generates a .rlib, which is
# a regular static library with extra metadata. However, if nothing
# outside the .rlib references functions in the .rlib—as is often the
# case with a target containing only tests—the linker will not pull in
# the .rlib into the final test binary at all, so the tests won't run.
#
# C++ works around this by using source sets and directly pass the .o
# files to the linker, but Rust does not have a parallel to this. Instead,
# force the linker to always include the whole archive.
#
# The library name is hardcoded here, since `get_target_outputs()` can't
# be used with a target that doesn't exist yet!
_rlib_path = "lib${_target_name}.rlib"
if (current_os == "aix") {
# The AIX linker does not implement an option for this.
} else if (is_win) {
ldflags = [ "/WHOLEARCHIVE:${_rlib_path}" ]
} else {
ldflags = [ "-LinkWrapper,add-whole-archive=${_rlib_path}" ]
}
}
_all_dependent_configs += [ ":${target_name}_alwayslink" ]
_configs += [ "//build/rust:is_gtest_unittests" ]
}
rust_target(_target_name) {
forward_variables_from(invoker,
"*",
TESTONLY_AND_VISIBILITY + [ "configs" ])
forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
library_configs = _configs
all_dependent_configs = _all_dependent_configs
target_type = "rust_library"
}
}
set_defaults("rust_static_library") {
configs = default_compiler_configs
}