123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- # Copyright 2021 The Chromium 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/rust.gni")
- import("//build/rust/rust_unit_test.gni")
- # The //build directory is re-used for non-Chromium products. We do not
- # support cxx/autocxx bindings in such contexts, because
- # //third_party may be missing.
- if (build_with_chromium) {
- import("//third_party/rust/autocxx/chromium_integration/rust_autocxx.gni")
- }
- # Creates a Rust target (rlib, executable, proc macro etc.) with
- # ability to understand some handy variables such as "edition" and
- # "features" and also to build any associated unit tests.
- #
- # Normally, you should not use this directly. Use either
- # - cargo_crate.gni - for 3p crates only
- # - rust_static_library.gni - for 1p Rust code
- # - mixed_static_library.gni - for 1p C++ and Rust code together.
- #
- # Because the common use of this is rust_static_library, all the documentation
- # for the supported options is given in rust_static_library.gni. Please refer
- # over there.
- #
- # If you're using rust_target directly, you will also need to specify:
- # target_type
- # executable, rust_library etc. per GN norms
- #
- # support_use_from_cpp (bool)
- # Whether both C++ and Rust may link against this. If so, the Rust standard
- # library will be explicitly included for C++ to link against. This is
- # always true if cxx_bindings is non-empty, in which case [auto]cxx
- # will also be implicitly depended on.
- #
- # There is one area where this differs from `rust_static_library`: configs.
- # Here, you must specify `executable_configs` or `library_configs`
- # depending on the type of thing you're generating. This is so that
- # different defaults can be provided.
- template("rust_target") {
- # Only one of `crate_root` or `generate_crate_root` can be specified, or
- # neither.
- assert(!defined(invoker.crate_root) ||
- !(defined(invoker.generate_crate_root) && invoker.generate_crate_root))
- _target_name = target_name
- _crate_name = target_name
- if (defined(invoker.crate_name)) {
- _crate_name = invoker.crate_name
- }
- if (defined(invoker.output_dir) && invoker.output_dir != "") {
- _out_dir = invoker.output_dir
- } else {
- _out_dir = target_out_dir
- }
- if (defined(invoker.generate_crate_root) && invoker.generate_crate_root) {
- generated_file("${_target_name}_crate_root") {
- outputs = [ "${target_gen_dir}/${target_name}.rs" ]
- contents = [
- "// Generated crate root for ${_target_name}.",
- "// @generated",
- "",
- ]
- foreach(rs, invoker.sources) {
- rs_path_from_root = rebase_path(rs, target_gen_dir)
- contents += [ "#[path = \"${rs_path_from_root}\"]" ]
- # Drop the file extension from the module name.
- rs_modname = string_replace(rs, ".rs", "")
- # Replace invalid "/" chars in the source file path.
- rs_modname = string_replace(rs_modname, "/", "_")
- # Since source files are specified relative to the BUILD.gn they may
- # also have ".." path components.
- rs_modname = string_replace(rs_modname, "..", "dotdot")
- contents += [
- "mod ${rs_modname};",
- "",
- ]
- }
- }
- _crate_root =
- string_join("", get_target_outputs(":${_target_name}_crate_root"))
- } else if (defined(invoker.crate_root)) {
- _crate_root = invoker.crate_root
- } else if (invoker.target_type == "executable") {
- _crate_root = "src/main.rs"
- } else {
- _crate_root = "src/lib.rs"
- }
- _testonly = false
- if (defined(invoker.testonly)) {
- _testonly = invoker.testonly
- }
- if (defined(invoker.visibility)) {
- _visibility = invoker.visibility
- }
- _rustflags = []
- if (defined(invoker.rustflags)) {
- _rustflags += invoker.rustflags
- }
- if (defined(invoker.features)) {
- foreach(i, invoker.features) {
- _rustflags += [ "--cfg=feature=\"${i}\"" ]
- }
- }
- _edition = "2021"
- if (defined(invoker.edition)) {
- _edition = invoker.edition
- }
- _configs = [ string_join("",
- [
- "//build/rust:edition_",
- _edition,
- ]) ]
- if (invoker.target_type == "executable") {
- if (defined(invoker.executable_configs)) {
- _configs += invoker.executable_configs
- }
- } else {
- if (defined(invoker.library_configs)) {
- _configs += invoker.library_configs
- }
- }
- _forward_to_host_toolchain = false
- if (invoker.target_type == "rust_proc_macro") {
- # TODO(crbug.com/gn/104): GN rust_proc_macro targets are missing this
- # command line flag, for the proc_macro crate which is provided by rustc for
- # compiling proc-macros.
- _rustflags += [
- "--extern",
- "proc_macro",
- ]
- if (current_toolchain != host_toolchain) {
- _forward_to_host_toolchain = true
- }
- _main_target_suffix = "${target_name}__proc_macro"
- } else {
- _main_target_suffix = "__rlib"
- }
- _deps = []
- if (defined(invoker.deps)) {
- _deps += invoker.deps
- }
- _public_deps = []
- if (defined(invoker.public_deps)) {
- _public_deps += invoker.public_deps
- }
- _build_unit_tests = false
- if (defined(invoker.build_native_rust_unit_tests)) {
- _build_unit_tests =
- invoker.build_native_rust_unit_tests && can_build_rust_unit_tests
- }
- # Declares that the Rust crate generates bindings between C++ and Rust via the
- # Cxx/autocxx crates. It may generate C++ headers and/or use the cxx crate macros
- # to generate Rust code internally, depending on what bindings are declared. If
- # set, it's a set of rust files that include Cxx or autocxx bindings declarations.
- _cxx_bindings = []
- if (defined(invoker.cxx_bindings)) {
- assert(
- build_with_chromium,
- "cxx/autocxx bindings are not supported when building rust targets " +
- "outside the Chromium build.")
- _cxx_bindings = invoker.cxx_bindings
- }
- _rustenv = []
- if (defined(invoker.rustenv)) {
- _rustenv += invoker.rustenv
- }
- foreach(_autocxx_generated, _cxx_bindings) {
- # TODO(crbug.com/1306841): Currently we support only a single
- # include_cpp! macro per target and this ugly environment
- # variable is necessary. Meanwhile, this path must match that of
- # out_gen0_rs in rust_autocxx.gni.
- _rustenv += [ "AUTOCXX_RS_FILE=" + rebase_path(
- "$target_gen_dir/$_autocxx_generated/gen0.include.rs") ]
- }
- # Normally we generate a C++ bindings group only if there are C++ bindings,
- # since it's not useful otherwise. But mixed targets want to be able to depend
- # on the Rust side regardless, or other Rust targets that provide interop
- # without using Cxx to generate bindings (such as via #[no_mangle] functions).
- _support_use_from_cpp = _cxx_bindings != []
- if (defined(invoker.support_use_from_cpp) && invoker.support_use_from_cpp) {
- _support_use_from_cpp = true
- }
- if (defined(invoker.mutually_dependent_target)) {
- _mutually_dependent_target = invoker.mutually_dependent_target
- _mutually_dependent_public_deps = invoker.mutually_dependent_public_deps
- } else {
- assert(!defined(_mutually_dependent_public_deps))
- }
- # TODO(danakj): This could be a hash generated from the input crate, such as
- # from its path, in which case the BUILD.gn would not need to specify
- # anything. But GN doesn't give us a hash function to make that easy.
- _metadata = "0"
- if (defined(invoker.epoch)) {
- _metadata = invoker.epoch
- }
- # We require that all source files are listed, even though this is
- # not a requirement for rustc. The reason is to ensure that tools
- # such as `gn deps` give the correct answer, and thus we trigger
- # the right test suites etc. on code change.
- # TODO(crbug.com/1256930) - verify this is correct
- assert(defined(invoker.sources), "sources must be listed")
- if (_forward_to_host_toolchain) {
- # Redirect to the host toolchain.
- group(_target_name) {
- testonly = _testonly
- if (defined(_visibility)) {
- visibility = _visibility
- }
- public_deps =
- [ ":${_target_name}${_main_target_suffix}($host_toolchain)" ]
- }
- not_needed(invoker, "*")
- not_needed([
- "_build_unit_tests",
- "_crate_root",
- "_crate_name",
- "_cxx_bindings",
- "_deps",
- "_metadata",
- "_mutually_dependent_public_deps",
- "_mutually_dependent_target",
- "_out_dir",
- "_public_deps",
- "_rustenv",
- "_support_use_from_cpp",
- "_test_deps",
- "_testonly",
- "_visibility",
- "proc_macro_target",
- ])
- } else {
- group(_target_name) {
- testonly = _testonly
- if (defined(_visibility)) {
- visibility = _visibility
- }
- # Both the C++ bindings (if present) and the Rust crate should be treated
- # like direct dependencies, so we expose them both in public_deps.
- public_deps = [ ":${_target_name}${_main_target_suffix}" ]
- if (_support_use_from_cpp) {
- if (_cxx_bindings != []) {
- public_deps += [ ":${_target_name}_autocxx_generated" ]
- # Additionally, C++ bindings generated by Cxx can include C++ types
- # that come from the Cxx library, such as `rust::Str`. So any C++
- # target that depends on a rust target directly may need access to Cxx
- # as well, which means it must appear in public_deps.
- public_deps += [ "//build/rust:cxx_cppdeps" ]
- } else {
- # If we're supporting use from C++ but not using Cxx bindings, then we
- # just need to make sure C++ links in the Rust stdlib.
- deps = [ "//build/rust/std" ]
- }
- } else {
- # Mixed targets (which define the below) always enable use from C++.
- assert(!defined(_mutually_dependent_target))
- }
- }
- _rust_deps = _deps
- _rust_public_deps = _public_deps
- _autocxx_deps = _deps + _public_deps
- # In a mixed target, the C++ bindings may include headers from the C++
- # part of the mixed target. Those headers rely on being used with the
- # correct dependencies present.
- if (defined(_mutually_dependent_public_deps)) {
- _autocxx_deps += _mutually_dependent_public_deps
- }
- # The Rust target (and unit tests) need the autocxx & cxx crates when using
- # them to generate bindings - both are in autocxx_rustdeps. We also need
- # to depend upon the autocxx code generation step, since when we build
- # our Rust code, a procedural macro will look for a file generated by that
- # codegen step.
- if (_cxx_bindings != []) {
- _rust_deps +=
- [ "//third_party/rust/autocxx/chromium_integration:autocxx_rustdeps" ]
- # Generated bindings are a public dep so that the unit tests can include
- # them.
- _rust_public_deps += [ ":${_target_name}_autocxx_generated" ]
- }
- # You must go through the groups above to get to these targets.
- _visibility = []
- _visibility = [ ":${_target_name}" ]
- target(invoker.target_type, "${_target_name}${_main_target_suffix}") {
- forward_variables_from(invoker,
- "*",
- TESTONLY_AND_VISIBILITY + [
- "features",
- "deps",
- "public_deps",
- "rustflags",
- "rustenv",
- "configs",
- "output_dir",
- "unit_test_target",
- "test_inputs",
- ])
- testonly = _testonly
- visibility = _visibility
- crate_name = _crate_name
- crate_root = _crate_root
- configs = []
- configs = _configs
- deps = _rust_deps
- public_deps = _rust_public_deps
- rustflags = _rustflags
- rustflags += [ string_join("",
- [
- "-Cmetadata=",
- _metadata,
- ]) ]
- rustenv = _rustenv
- rustenv += [ "OUT_DIR=" + rebase_path(_out_dir) ]
- # The Rust tool() declarations, like C++ ones, use the output_name and
- # output_dir, so that GN targets can override these if needed. Here we
- # give them their default values, or allow them to be overridden.
- output_dir = _out_dir
- if (!defined(output_name) || output_name == "") {
- output_name = crate_name
- }
- }
- if (_cxx_bindings != []) {
- rust_autocxx("${_target_name}_autocxx_generated") {
- testonly = _testonly
- visibility = [ ":${_target_name}${_main_target_suffix}" ]
- if (defined(_visibility)) {
- visibility += _visibility
- }
- sources = _cxx_bindings
- deps = _autocxx_deps
- configs = _configs
- if (is_component_build) {
- # In a component_build the cxx bindings may be linked into a shared
- # library at any point up the dependency tree, so always export.
- export_symbols = true
- } else if (invoker.target_type == "shared_library") {
- export_symbols = true
- } else {
- export_symbols = false
- }
- }
- } else {
- not_needed([
- "_autocxx_deps",
- "_mutually_dependent_public_deps",
- ])
- }
- if (_build_unit_tests) {
- _unit_test_target = "${_target_name}_unittests"
- if (defined(invoker.unit_test_target)) {
- _unit_test_target = invoker.unit_test_target
- }
- rust_unit_test(_unit_test_target) {
- forward_variables_from(invoker, [ "sources" ])
- testonly = true
- crate_root = _crate_root
- rustflags = _rustflags
- output_dir = _out_dir
- deps = _rust_deps + _public_deps
- if (defined(invoker.test_deps)) {
- deps += invoker.test_deps
- }
- inputs = []
- if (defined(invoker.inputs)) {
- inputs += invoker.inputs
- }
- if (defined(invoker.test_inputs)) {
- inputs += invoker.test_inputs
- }
- if (defined(_mutually_dependent_target)) {
- # This routes through the C++ mixed target rule to get back to the
- # Rust $_target_name.
- public_deps = [ _mutually_dependent_target ]
- } else {
- public_deps = [ ":${_target_name}" ]
- }
- if (defined(invoker.executable_configs)) {
- configs = []
- configs = invoker.executable_configs
- }
- rustenv = _rustenv
- }
- } else {
- not_needed([
- "_crate_root",
- "_crate_name",
- "_metadata",
- "_mutually_dependent_target",
- ])
- }
- }
- }
- set_defaults("rust_target") {
- executable_configs = default_executable_configs
- library_configs = default_compiler_configs
- }
|