1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
|
# 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.
#
# data, testonly, visibility (optional)
# Same meaning as in other GN targets.
#
# crate_name (optional)
# Discouraged - first-party code should prefer to use the auto-generated,
# target-based crate name which is guaranteed to be globally unique (and
# still ergonomic to import and use via the `chromium::import!` macro).
#
# 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) {
_output_dir = rebase_path(target_out_dir, root_build_dir)
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.
# NOTE: TargetName=>CrateName mangling algorithm should be updated
# simultaneously in 3 places: here, //build/rust/rust_target.gni,
# //build/rust/chromium_prelude/import_attribute.rs
if (defined(invoker.crate_name)) {
_crate_name = invoker.crate_name
} else {
# Not using `get_label_info(..., "label_no_toolchain")` to consistently
# use `//foo/bar:baz` instead of the alternative shorter `//foo/bar` form.
_dir = get_label_info(":${_target_name}", "dir")
_dir = string_replace(_dir, "//", "")
_crate_name = "${_dir}:${_target_name}"
# The `string_replace` calls below replicate the escaping algorithm
# from the `escape_non_identifier_chars` function in
# //build/rust/chromium_prelude/import_attribute.rs. Note that the
# ordering of `match` branches within the Rust function doesn't matter,
# but the ordering of `string_replace` calls *does* matter - the escape
# character `_` needs to be handled first to meet the injectivity
# requirement (otherwise we would get `/` => `_s` => `_us` and the same
# result for `_s` => `_us`).
_crate_name = string_replace(_crate_name, "_", "_u")
_crate_name = string_replace(_crate_name, "/", "_s")
_crate_name = string_replace(_crate_name, ":", "_c")
_crate_name = string_replace(_crate_name, "-", "_d")
}
_rlib_path = "${_output_dir}/lib${_crate_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
}
|