tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }