| # 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_cxx.gni") |
| import("//build/rust/rust_static_library.gni") |
| import("//build/rust/rust_target.gni") |
| |
| # Defines a target containing both Rust and C++ code, with bidirectional calls. |
| # It's rare to use this target directly - instead please use |
| # mixed_static_library or, less commonly, mixed_component. |
| # |
| # This intent of this template is to make it as easy as possible to add Rust |
| # code into an existing C++ target. |
| # |
| # Important: downstream Rust targets should NOT depend upon this type of target. |
| # Instead they should append the suffix "_rs" when adding this to their deps: |
| # |
| # deps += [ "//example:foo_bar_rs" ] |
| # |
| # Downstream C++ targets should depend on this target directly. |
| # |
| # Parameters |
| # |
| # sources |
| # configs |
| # deps |
| # etc. etc. etc. |
| # Parameters for C++ target. All parameters not starting with |
| # 'rs_' are passed directly to the underlying C++ target |
| # (static_library, component etc.) |
| # |
| # rs_sources |
| # rs_epoch |
| # rs_edition |
| # rs_configs |
| # rs_deps |
| # rs_test_deps |
| # rs_skip_unit_tests |
| # rs_unit_test_target |
| # rs_crate_name |
| # rs_crate_root |
| # rs_features |
| # rs_cxx_bindings |
| # Rust parameters. Same meaning as in 'rust_static_library' without the |
| # 'rs_' prefix, e.g. rs_configs here means the same as 'configs' in |
| # rust_static_library. |
| # rs_visibility |
| # A special note on visibility. By default, the Rust parts of this |
| # mixed target are _only_ visible to the C++ parts. That's different |
| # from the normal visibility default which is "*", but is more |
| # commonly what you want. If you want visibility of "*" you should |
| # override this. |
| # |
| # In the event that Rust is not enabled in the build, this will produce a |
| # plain C/C++ target. |
| # |
| # If Rust is enabled, a #define ENABLE_RUST will be applied to the C/C++ |
| # code. |
| # |
| # Implementation note: this target generally leans heavily on the |
| # rust_static_library.gni template to build its Rust code (which in turn is |
| # just a rust_target.gni in slightly fancy clothes). However, the exception |
| # is for the C++ side of any cxx bindings. These are built and managed directly |
| # by this template instead of deferring to the facilities in rust_target.gni, |
| # because we want the resulting bindings to be built as part of the pre-existing |
| # C++ source_set. This is partly to reduce target proliferation, partly to avoid |
| # having to use 'allow_circular_includes' and deal with layering violations, |
| # and partly because other targets elsewhere in the codebase might have |
| # visibility rules which refer to this source_set by name, and wouldn't allow |
| # a C++/Rust bindings source_set to have visibility into the same headers. |
| |
| template("mixed_target") { |
| _target_name = target_name |
| |
| known_rs_variables = [ |
| "rs_epoch", |
| "rs_edition", |
| "rs_configs", |
| "rs_deps", |
| "rs_test_deps", |
| "rs_sources", |
| "rs_features", |
| "rs_cxx_bindings", |
| "rs_crate_name", |
| "rs_crate_root", |
| "rs_skip_unit_tests", |
| "rs_unit_test_target", |
| "rs_visibility", |
| ] |
| |
| _rs_enable = enable_rust |
| |
| # Conceivably, conditional statements in the template invocation |
| # might result in no rs_sources files. If so, don't build any Rust. |
| if (!defined(invoker.rs_sources) || invoker.rs_sources == []) { |
| _rs_enable = false |
| } |
| |
| if (_rs_enable) { |
| rust_static_library("${_target_name}_rs") { |
| # Normally we forward both testonly and visibility from the invoker. But |
| # here we exclude "visibility" since the Rust parts are only visible to |
| # the C++ parts of the same mixed target by default. |
| forward_variables_from(invoker, TESTONLY_AND_VISIBILITY, [ "visibility" ]) |
| mutually_dependent_target = ":${_target_name}" |
| if (defined(invoker.rs_epoch)) { |
| epoch = invoker.rs_epoch |
| } |
| if (defined(invoker.rs_edition)) { |
| edition = invoker.rs_edition |
| } |
| if (defined(invoker.rs_configs)) { |
| # The `configs` will always be non-empty due to `set_defaults()` which |
| # sets them for each type of rust target. |
| configs += invoker.rs_configs |
| } |
| if (defined(invoker.rs_test_deps)) { |
| test_deps = invoker.rs_test_deps |
| } |
| if (defined(invoker.rs_sources)) { |
| sources = invoker.rs_sources |
| } |
| if (defined(invoker.rs_features)) { |
| features = invoker.rs_features |
| } |
| if (defined(invoker.rs_deps)) { |
| deps = invoker.rs_deps |
| } |
| if (defined(invoker.rs_crate_root)) { |
| crate_root = invoker.rs_crate_root |
| } |
| if (defined(invoker.rs_crate_name)) { |
| crate_name = invoker.rs_crate_name |
| } |
| if (defined(invoker.rs_skip_unit_tests)) { |
| skip_unit_tests = invoker.rs_skip_unit_tests |
| } |
| if (defined(invoker.rs_unit_test_target)) { |
| unit_test_target = invoker.rs_unit_test_target |
| } |
| if (defined(invoker.testonly) && invoker.testonly) { |
| testonly = true |
| } |
| visibility = [ ":${_target_name}" ] |
| if (defined(invoker.rs_visibility)) { |
| visibility += invoker.rs_visibility |
| } |
| if (defined(invoker.rs_cxx_bindings)) { |
| if (!defined(deps)) { |
| deps = [] |
| } |
| deps += [ "//build/rust:cxx_rustdeps" ] |
| } |
| } |
| } else { |
| not_needed(invoker, known_rs_variables) |
| } |
| |
| target(invoker.target_type, _target_name) { |
| forward_variables_from(invoker, "*", known_rs_variables + [ "target_type" ]) |
| if (_rs_enable) { |
| if (!defined(deps)) { |
| deps = [] |
| } |
| |
| # C++ source set depends on the Rust source set |
| # plus any other things it required C++ targets |
| # to depend upon (likely the Rust stdlib). This |
| # does not include cxx bindings, which we create |
| # below. |
| deps += [ ":${_target_name}_rs_cpp_bindings" ] |
| if (!defined(configs)) { |
| configs = [] |
| } |
| if (defined(invoker.rs_cxx_bindings)) { |
| deps += [ |
| # Generate the C++ side of any Rust bindings. |
| # We will use the generated source code just below. |
| ":${_target_name}_rs_cxx_gen", |
| |
| # Also, depend on the cxx 'standard library', |
| # i.e. utilities which any user of cxx needs to |
| # have. |
| "//build/rust:cxx_cppdeps", |
| ] |
| if (!defined(sources)) { |
| sources = [] |
| } |
| |
| # Depend on the generated sources which are the C++ |
| # side of the cxx bindings. |
| sources += process_file_template( |
| invoker.rs_cxx_bindings, |
| [ |
| "{{source_gen_dir}}/{{source_file_part}}.h", |
| "{{source_gen_dir}}/{{source_file_part}}.cc", |
| ]) |
| } |
| if (defined(visibility)) { |
| visibility += [ ":${_target_name}_rs" ] |
| if (!defined(invoker.rs_skip_unit_tests) || |
| !invoker.rs_skip_unit_tests) { |
| _unit_test_target = "${_target_name}_rs_unittests" |
| if (defined(invoker.rs_unit_test_target)) { |
| _unit_test_target = invoker.rs_unit_test_target |
| } |
| visibility += [ ":${_unit_test_target}_exe" ] |
| } |
| } |
| } |
| } |
| |
| if (_rs_enable && defined(invoker.rs_cxx_bindings)) { |
| rust_cxx("${_target_name}_rs_cxx") { |
| 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 |
| } |
| inputs = invoker.rs_cxx_bindings |
| generate_source_set = false |
| } |
| } |
| } |