| # Copyright 2022 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/config/clang/clang.gni") |
| import("//build/config/rust.gni") |
| import("//build/config/sysroot.gni") |
| import("//build/rust/gni_impl/rustc_print_cfg.gni") |
| |
| set_defaults("rust_cxx") { |
| native_header_deps = [] |
| } |
| |
| # Template to build Rust/C++ bindings using the tooling |
| # described at https://cxx.rs. |
| # |
| # (Specifically, this builds the C++ side of the bindings. |
| # The Rust side of the bindings are not 'built' as such, but |
| # automatically expanded by the Rust compiler by virtue of a |
| # proc macro which is a simple dependency relationship on the |
| # Rust target). |
| # |
| # This template expands to a source_set containing the |
| # C++ side of the bindings. Simply treat it as a dependency. |
| # |
| # If you're using this, consider whether you should be using |
| # rust_static_library.gni or mixed_static_library.gni which have |
| # facilities to do the same code generation in an easier |
| # way. |
| # |
| # Parameters: |
| # |
| # sources: |
| # The .rs files containing a #[cxx::bridge] section. |
| # |
| # deps (optional) |
| # C++ targets on which the headers depend in order to build |
| # successfully. |
| # |
| # export_symbols |
| # Whether the C++ side of the bindings should be exported |
| # from any shared objects in which it finds itself. |
| # This is not necessary if the Rust and C++ side of the |
| # bindings will always find themselves within the same binary, |
| # which is usually the case in a non-component build. |
| # Even in a component build, the Rust and C++ code will |
| # often find itself within the same binary and no exporting |
| # is required. However, there may be other binaries - most |
| # commonly Rust unit test executables - which contain the |
| # Rust side of the bindings but not the C++ side. In such |
| # a case, it's important that the C++ side symbols are |
| # exported such that the Rust unit tests can link against |
| # them. This does the equivalent of adding BASE_EXPORT |
| # or similar. |
| # Example: |
| # Non-component build: |
| # group of libfoo.a, foo.rlib # contain |
| # # C++ and Rust side bindings, always both linked |
| # # into final targets |
| # foo_rs_unittests # contains Rust side bindings, |
| # # and any C++ dependencies which will include |
| # # all of the libfoo code. |
| # Component build: |
| # libfoo.so # contains C++ and Rust side bindings |
| # foo_rs_unittests # contains Rust side test code, |
| # # but links against libfoo.so to get the C++ |
| # # side bindings. So libfoo.so must make those |
| # # symbols visible. |
| template("rust_cxx") { |
| assert(defined(invoker.sources), |
| "Must specify the Rust file to use as input.") |
| _target_name = target_name |
| _testonly = false |
| if (defined(invoker.testonly)) { |
| _testonly = invoker.testonly |
| } |
| if (defined(invoker.visibility)) { |
| _visibility = invoker.visibility |
| } |
| |
| action_foreach("${_target_name}_gen") { |
| testonly = _testonly |
| visibility = [ ":${_target_name}" ] |
| if (defined(_visibility)) { |
| visibility += _visibility |
| } |
| |
| sources = invoker.sources |
| |
| output_h = "{{source_gen_dir}}/{{source_file_part}}.h" |
| output_cc = "{{source_gen_dir}}/{{source_file_part}}.cc" |
| |
| # Below we use $rust_macro_toolchain rather than $host_toolchain since we |
| # are building a standalone Rust target that is not part of the Chromium |
| # production build, and this unblocks it from building while the Chromium |
| # stdlib is still compiling, further freeing up other Rust proc-macro |
| # targets (if they used cxxbridge for some reason). |
| cxxbridge_target = |
| "//third_party/rust/cxxbridge_cmd/v1:cxxbridge($rust_macro_toolchain)" |
| |
| cxxbridge_out_dir = get_label_info(cxxbridge_target, "root_out_dir") |
| cxxbridge_executable = "${cxxbridge_out_dir}/cxxbridge" |
| |
| # The executable is always built with the `rust_macro_toolchain` which |
| # targets the `host_os`. The rule here is on the `target_toolchain` which |
| # can be different (e.g. compiling on Linux, targeting Windows). |
| if (host_os == "win") { |
| cxxbridge_executable = "${cxxbridge_executable}.exe" |
| } |
| |
| script = "//third_party/rust/cxx/chromium_integration/run_cxxbridge.py" |
| inputs = [ |
| cxxbridge_executable, |
| script, |
| rustc_print_cfg_path, |
| ] |
| outputs = [ |
| output_h, |
| output_cc, |
| ] |
| deps = [ |
| "//build/rust/gni_impl:rustc_print_cfg", |
| cxxbridge_target, |
| ] |
| |
| args = [ |
| "--exe", |
| rebase_path(cxxbridge_executable, root_build_dir), |
| "--header", |
| output_h, |
| "--cc", |
| output_cc, |
| "--rustc-print-cfg-path", |
| rebase_path(rustc_print_cfg_path, root_build_dir), |
| "{{source}}", |
| "--", |
| ] |
| |
| if (invoker.export_symbols) { |
| # See explanation of 'export_symbols' above for what this does. |
| # Implementation note: we could have required users of this template to |
| # specify a preprocessor symbol, e.g. BASE_EXPORT, which would vary |
| # per-component. However, since we're building only the definition of the |
| # bindings, not any header files, the export specifications are |
| # predictable and we don't need to foist that complexity on users of this |
| # template. The default behavior here should be correct. If this proves to |
| # be insufficient in future, this template should be modified to accept a |
| # parameter where users can specify 'BASE_EXPORT' or the equivalent for |
| # their component. cxxbridge --cxx-impl-annotations adds this annotation |
| # to each exported C++ function. |
| args += [ "--cxx-impl-annotations" ] |
| if (is_win) { |
| args += [ "__declspec(dllexport)" ] |
| } else { |
| args += [ "__attribute__((visibility(\"default\")))" ] |
| } |
| } |
| } |
| |
| static_library(target_name) { |
| forward_variables_from(invoker, [ "deps" ]) |
| |
| testonly = _testonly |
| if (defined(invoker.visibility)) { |
| visibility = invoker.visibility |
| } |
| sources = get_target_outputs(":${target_name}_gen") |
| if (!defined(deps)) { |
| deps = [] |
| } |
| deps += [ |
| ":${target_name}_gen", |
| "//build/rust:cxx_cppdeps", |
| ] |
| if (defined(invoker.configs)) { |
| configs = [] |
| configs = invoker.configs |
| } |
| } |
| } |