| # Copyright 2026 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/toolchain/kythe.gni") |
| |
| # Defines a C++ `source_set` (and supporting targets) that contains C++ |
| # bindings for using/calling-into a given Rust crate. |
| # |
| # `cpp_api_from_rust.gni` should only be `import`ed from |
| # `gni_impl/rust_target.gni`. The public way to use these bindings is the |
| # `cpp_api_from_rust` parameter of `rust_static_library` and/or `cargo_crate` |
| # templates. |
| # |
| # Parameters |
| # |
| # rust_target |
| # Label of the Rust library to generate the bindings for. |
| # |
| # rustc_env_and_flags |
| # Path to the `.rustflags.json` file generated by an earlier invocation |
| # of `rustc`. (`cpp_api_from_rust` needs to be invoked with the same |
| # arguments, target platform, etc. as `rust_target`.) |
| # |
| # crate_name |
| # Name (potentially mangled/auto-generated) of the crate that `rust_target` |
| # is built into. |
| # |
| # original_attributes |
| # The original `cc_bindings_from_rs = { ... }` dictionary (the value of |
| # the `cc_bindings_from_rs` attribute of a target like |
| # `rust_static_library`). |
| # |
| # sources |
| # deps |
| # Dependencies for compiling `rust_target`. |
| # |
| # |
| template("cpp_api_from_rust") { |
| _rspgen_target_name = "${target_name}_crubit_rspgen" |
| _action_target_name = "${target_name}_crubit_action" |
| _rust_impl_target_name = "${target_name}_crubit_impl" |
| _h_target_name = target_name |
| |
| assert(defined(invoker.deps)) |
| assert(defined(invoker.sources)) |
| assert(defined(invoker.rustc_env_and_flags)) |
| assert(defined(invoker.rust_target)) |
| assert(defined(invoker.original_attributes)) |
| assert(defined(invoker.crate_name)) |
| _crate_name = invoker.crate_name |
| _rust_target = invoker.rust_target |
| _rust_target_name = get_label_info(_rust_target, "name") |
| _h_out = "${target_gen_dir}/${_rust_target_name}.h" |
| _rs_out = "${_h_out}.impl.rs" |
| |
| _crubit_support_path_format = |
| "\"third_party/rust-toolchain/lib/crubit/support/{header}\"" |
| _cpp_api_from_rust_exe_path = |
| "//third_party/rust-toolchain/bin/cc_bindings_from_rs" |
| _rustfmt_exe_path = "//third_party/rust-toolchain/bin/rustfmt" |
| _rustfmt_config_path = "//.rustfmt.toml" |
| if (host_os == "win") { |
| _cpp_api_from_rust_exe_path += ".exe" |
| _rustfmt_exe_path += ".exe" |
| } |
| |
| # TODO(lukasza): Make this also work on other host platforms. (Possibly |
| # hoisting this `cpp_api_from_rust`-agnostic functionality into some other, |
| # reusable location elsewhere.) |
| if (host_os == "linux") { |
| _clang_format_exe_path = "//buildtools/linux64-format/clang-format" |
| } else if (host_os == "win") { |
| _clang_format_exe_path = "//buildtools/win-format/clang-format.exe" |
| } |
| |
| _action_rsp_path = "$target_out_dir/$_action_target_name.rsp" |
| generated_file(_rspgen_target_name) { |
| forward_variables_from(invoker, [ "testonly" ]) |
| forward_variables_from(invoker.original_attributes, [ "deps" ]) |
| outputs = [ _action_rsp_path ] |
| data_keys = [ "crate_header" ] |
| walk_keys = [] # Only metadata of direct, non-transitive `deps`. |
| visibility = [ ":${_action_target_name}" ] |
| } |
| |
| action(_action_target_name) { |
| forward_variables_from(invoker, |
| [ |
| "sources", |
| "deps", |
| "testonly", |
| ]) |
| deps += [ ":${_rspgen_target_name}" ] |
| |
| visibility = [ |
| ":$_h_target_name", |
| ":$_rust_impl_target_name", |
| ] |
| |
| script = "//build/rust/gni_impl/cpp_api_from_rust_wrapper.py" |
| inputs = [ |
| # `import`ed for `LoadRustEnvAndFlags`, etc. |
| "//build/rust/gni_impl/rustc_wrapper.py", |
| |
| # Tools / executables: |
| _cpp_api_from_rust_exe_path, |
| _rustfmt_exe_path, |
| _rustfmt_config_path, |
| ] |
| outputs = [ |
| _h_out, |
| _rs_out, |
| ] |
| |
| # `cpp_api_from_rust_wrapper.py` flags: |
| args = [ |
| "--cpp-api-from-rust-exe-path", |
| rebase_path(_cpp_api_from_rust_exe_path, root_build_dir), |
| |
| "--rustc-env-and-flags", |
| rebase_path(invoker.rustc_env_and_flags, root_build_dir), |
| "@" + rebase_path(_action_rsp_path, root_build_dir), |
| ] |
| |
| # `cpp_api_from_rust` flags: |
| args += [ |
| "--", |
| |
| "--h-out", |
| rebase_path(_h_out, root_build_dir), |
| |
| "--rs-out", |
| rebase_path(_rs_out, root_build_dir), |
| |
| "--crubit-support-path-format", |
| _crubit_support_path_format, |
| |
| "--rustfmt-exe-path", |
| rebase_path(_rustfmt_exe_path, root_build_dir), |
| |
| "--rustfmt-config-path", |
| rebase_path(_rustfmt_config_path, root_build_dir), |
| |
| # TODO(crbug.com/470466915): Start using `--crate-namespace...` to stop |
| # leaking mangled crate name via namespace of the generated bindings. |
| # This may be blocked by b/473633643. |
| ] |
| if (defined(_clang_format_exe_path)) { |
| inputs += [ _clang_format_exe_path ] |
| args += [ |
| "--clang-format-exe-path", |
| rebase_path(_clang_format_exe_path, root_build_dir), |
| ] |
| } |
| if (enable_kythe_annotations) { |
| args += [ |
| "--kythe-annotations", |
| "--kythe-default-corpus", |
| kythe_corpus_identifier, |
| ] |
| } |
| } |
| |
| # Using `rust_library` instead of `rust_static_library` to minimize |
| # dependencies of `cpp_api_from_rust.gni` (otherwise `import`ing |
| # `cpp_api_from_rust.gni` from `rust_target.gni` would lead to |
| # a cycle). |
| rust_library(_rust_impl_target_name) { |
| forward_variables_from(invoker, |
| [ |
| "deps", |
| "testonly", |
| ]) |
| if (!defined(deps)) { |
| deps = [] |
| } |
| deps += [ |
| ":$_action_target_name", |
| "//build/rust/crubit:cpp_api_from_rust_bindings_rs_deps", |
| _rust_target, |
| ] |
| visibility = [ ":$_h_target_name" ] |
| |
| # Without going through `rust_static_library` / `rust_target` we have to |
| # implement our own little mangling scheme. Thankfully, the only user |
| # of this crate is `_h_target_name`, which only consumes C ABI top-level |
| # entrypoints - this means that the crate name isn't used / doesn't leak |
| # anywhere. And therefore it doesn't matter what kind of mangling we do, |
| # as long as we ensure that it is globally unique. |
| _crate_name_suffix = |
| string_hash(get_label_info(_rust_target_name, "label_with_toolchain")) |
| crate_name = "${_rust_target_name}_crubit_${_crate_name_suffix}" |
| output_name = crate_name |
| |
| crate_root = _rs_out |
| sources = [ crate_root ] |
| configs += [ "//build/rust:default_edition" ] |
| } |
| |
| source_set(_h_target_name) { |
| forward_variables_from(invoker, TESTONLY_AND_VISIBILITY) |
| |
| forward_variables_from(invoker.original_attributes, [ "deps" ]) |
| if (!defined(deps)) { |
| deps = [] |
| } |
| deps += [ |
| ":$_action_target_name", |
| ":$_rust_impl_target_name", |
| "//build/rust/crubit:cpp_api_from_rust_bindings_cpp_deps", |
| ] |
| |
| _gen_dir_relative_h_out = rebase_path(_h_out, root_gen_dir) |
| metadata = { |
| crate_header = |
| [ "--crate-header=${_crate_name}=${_gen_dir_relative_h_out}" ] |
| } |
| |
| public = [ _h_out ] |
| } |
| } |