rust_static_library.gni (9527B)
1 # Copyright 2021 The Chromium Authors 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import("//chromium/build/rust/rust_target.gni") 6 7 # Defines a Rust static library which can be used by downstream Rust or C++ 8 # targets. This is a single Rust compilation unit consisting of potentially 9 # multiple .rs files. 10 # 11 # We term this 'rust_static_library' because it is used most analogously 12 # to a C++ 'static_library' in Chromium. Like the C++ one, it can be compiled 13 # independently into an intermediate linking target. The output contains the 14 # object file(s) of the GN target's sources, and not its dependencies. 15 # 16 # Parameters 17 # 18 # sources 19 # List of source files which this crate is allowed to compile, which is 20 # used to determine the impact of source code changes on other GN targets. 21 # This is not used by the Rust compiler, as it discovers source files by 22 # following `mod` declarations starting at the `crate_root`. The 23 # discovered source files must match this list. (This is not yet enforced, 24 # but will be.) 25 # 26 # edition (optional) 27 # Edition of the Rust language to be used. 28 # Options are "2015", "2018" and "2021". Defaults to "2021". 29 # 30 # allow_unsafe (optional) 31 # Set to true to allow unsafe code in this target. Defaults to false. 32 # 33 # configs (optional) 34 # A list of config labels (in the GN meaning) applying to this target. 35 # 36 # rustflags (optional) 37 # Explicit flags for rustc command line. (Use 'edition' or 'features' 38 # where possible). 39 # 40 # deps (optional) 41 # List of GN targets on which this crate depends. These may be Rust 42 # or non-Rust targets. 43 # 44 # public_deps (optional) 45 # List of GN targets on which this crate depends, and which are exported 46 # into the dependency list of any crate that depends on it. Dependency 47 # crates that appear in the public API should be included here. 48 # 49 # test_deps (optional) 50 # List of GN targets on which this crate's tests depend, in addition 51 # to deps. 52 # 53 # is_gtest_unittests (optional) 54 # Should only be set to true for rlibs of gtest unit tests. This ensures 55 # all objects in the rlib are linked into the final target, rather than 56 # pruning dead code, so that the tests themselves are not discarded by the 57 # linker. 58 # 59 # mutually_dependent_target (optional) 60 # mutually_dependent_public_deps (optional) 61 # These is for use by the mixed_target() template. 62 # 63 # If this Rust code is intrinsically paired with some C/C++ code, 64 # with bidirectional calls between the two, then this would 65 # be a circular dependency. GN does not allow circular dependencies, 66 # (other than for header files per allow_circular_includes_from). 67 # But this is common for a 'component' which has both Rust and C++ 68 # code. You should structure things such that the C++ code depends 69 # on the Rust code in the normal way: 70 # static_library("cpp_stuff") { 71 # deps = [ "rust_stuff" ] 72 # # .. 73 # } 74 # but that the Rust target also notes the C++ target using this 75 # 'mutually_dependent_target' parameter. 76 # rust_static_library("rust_stuff") { 77 # mutually_dependent_target = "cpp_stuff" 78 # mutually_dependent_public_deps = _cpp_stuff_public_deps 79 # # .. 80 # } 81 # 82 # This causes the Rust unit tests, if generated, to depend on the mutually 83 # dependent target, since depending on the Rust code only would be 84 # insufficient. And it allows any C++ bindings generated from the Rust code 85 # to include headers from the mutually_dependent_target by depending on its 86 # public_deps. 87 # 88 # build_native_rust_unit_tests (optional) 89 # Builds native unit tests (under #[cfg(test)]) written inside the Rust 90 # crate. This will create a `<name>_unittests` executable in the output 91 # directory when set to true. 92 # 93 # unit_test_target (optional) 94 # Overrides the default name for the unit tests target 95 # 96 # crate_root (optional) 97 # Location of the crate root. 98 # This defaults to `./src/lib.rs` and should only be changed when 99 # absolutely necessary (such as in the case of generated code). 100 # 101 # features (optional) 102 # A list of conditional compilation flags to enable. This can be used 103 # to set features for crates built in-tree which are also published to 104 # crates.io. Each feature in the list will be passed to rustc as 105 # '--cfg feature=XXX' 106 # 107 # cxx_bindings (optional) 108 # A list of Rust files which contain #[cxx::bridge] mods and should 109 # therefore have C++ bindings generated. See https://cxx.rs. 110 # This will automatically add appropriate dependencies: there's no 111 # need to depend on the cxx crate or any generated bindings. 112 # 113 # data, testonly, visibility (optional) 114 # Same meaning as in other GN targets. 115 # 116 # crate_name (optional) 117 # Discouraged - first-party code should prefer to use the auto-generated, 118 # target-based crate name which is guaranteed to be globally unique (and 119 # still ergonomic to import and use via the `chromium::import!` macro). 120 # 121 # inputs (optional) 122 # Additional input files needed for compilation (such as `include!`ed files) 123 # 124 # test_inputs (optional) 125 # Same as above but for the unit tests target 126 # 127 # rustc_metadata (optional) 128 # Override the metadata identifying the target's version. This allows e.g. 129 # linking otherwise conflicting versions of the same Rust library. The 130 # metadata string will also be appended to the output library names. 131 # Should be used sparingly, since generally we should have one version and 132 # build of each target. 133 # 134 # Example of usage: 135 # 136 # rust_static_library("foo_bar") { 137 # deps = [ 138 # "//boo/public/rust/bar", 139 # "//third_party/rust/crates:argh", 140 # "//third_party/rust/crates:serde", 141 # "//third_party/rust/crates:slab", 142 # ] 143 # sources = [ "src/lib.rs" ] 144 # } 145 # 146 # This template is intended to serve the same purpose as 'rustc_library' 147 # in Fuchsia. 148 template("rust_static_library") { 149 _target_name = target_name 150 151 _configs = [] 152 _all_dependent_configs = [] 153 154 if (defined(invoker.configs)) { 155 _configs += invoker.configs 156 } 157 158 # TODO(dcheng): Is there any value in allowing rust_shared_library() to also 159 # set `is_gtest_unittest` to true? 160 if (defined(invoker.is_gtest_unittests) && invoker.is_gtest_unittests) { 161 _output_dir = rebase_path(target_out_dir, root_build_dir) 162 163 config("${_target_name}_alwayslink") { 164 # Targets using the #[gtest(...)] proc macro register their tests with 165 # static initializers. A rust library target generates a .rlib, which is 166 # a regular static library with extra metadata. However, if nothing 167 # outside the .rlib references functions in the .rlib—as is often the 168 # case with a target containing only tests—the linker will not pull in 169 # the .rlib into the final test binary at all, so the tests won't run. 170 # 171 # C++ works around this by using source sets and directly pass the .o 172 # files to the linker, but Rust does not have a parallel to this. Instead, 173 # force the linker to always include the whole archive. 174 175 # NOTE: TargetName=>CrateName mangling algorithm should be updated 176 # simultaneously in 3 places: here, //build/rust/rust_target.gni, 177 # //build/rust/chromium_prelude/import_attribute.rs 178 if (defined(invoker.crate_name)) { 179 _crate_name = invoker.crate_name 180 } else { 181 # Not using `get_label_info(..., "label_no_toolchain")` to consistently 182 # use `//foo/bar:baz` instead of the alternative shorter `//foo/bar` form. 183 _dir = get_label_info(":${_target_name}", "dir") 184 _dir = string_replace(_dir, "//", "") 185 _crate_name = "${_dir}:${_target_name}" 186 187 # The `string_replace` calls below replicate the escaping algorithm 188 # from the `escape_non_identifier_chars` function in 189 # //build/rust/chromium_prelude/import_attribute.rs. Note that the 190 # ordering of `match` branches within the Rust function doesn't matter, 191 # but the ordering of `string_replace` calls *does* matter - the escape 192 # character `_` needs to be handled first to meet the injectivity 193 # requirement (otherwise we would get `/` => `_s` => `_us` and the same 194 # result for `_s` => `_us`). 195 _crate_name = string_replace(_crate_name, "_", "_u") 196 _crate_name = string_replace(_crate_name, "/", "_s") 197 _crate_name = string_replace(_crate_name, ":", "_c") 198 _crate_name = string_replace(_crate_name, "-", "_d") 199 } 200 201 _rlib_path = "${_output_dir}/lib${_crate_name}.rlib" 202 if (current_os == "aix") { 203 # The AIX linker does not implement an option for this. 204 } else if (is_win) { 205 ldflags = [ "/WHOLEARCHIVE:${_rlib_path}" ] 206 } else { 207 ldflags = [ "-LinkWrapper,add-whole-archive=${_rlib_path}" ] 208 } 209 } 210 _all_dependent_configs += [ ":${target_name}_alwayslink" ] 211 _configs += [ "//chromium/build/rust:is_gtest_unittests" ] 212 } 213 214 rust_target(_target_name) { 215 forward_variables_from(invoker, 216 "*", 217 TESTONLY_AND_VISIBILITY + [ "configs" ]) 218 forward_variables_from(invoker, TESTONLY_AND_VISIBILITY) 219 library_configs = _configs 220 all_dependent_configs = _all_dependent_configs 221 target_type = "rust_library" 222 } 223 } 224 225 set_defaults("rust_static_library") { 226 configs = default_compiler_configs 227 }