0

Expose a rust_static_library instead of raw rs file from rust_bindgen

Originally, `rust_bindgen` would originally expose an `action` which
generates a `.rs` file (and sometimes `.c` file if wrap_static_inline
is true). This would move the burden of knowing how to correctly bundle
the generated file on the user where they would have to define a custom
`BINDGEN_RS_FILE` flag which has to be loaded from the code.

In order to eliminate the overhead, the user will treat the
`rust_bindgen` as a `rust_static_library` which can be used by importing
it using `chromium::import` or `use ..` whether it's first-party or not.

The different design also allows the rust toolchain owners to take
finer control on what's being done and what's exposed exactly from
`rust_bindgen` by tweaking the `bindings.rs` file.

This also fixes Cronet in AOSP where Soong (AOSP build system) does not
allow a target to access another target's output through its path which
what most clients of `rust_bindgen` did through the custom rustflag.

In order to stay backward compatible with older consumers of
`rust_bindgen`, we created `rust_bindgen_generator` which generates the
raw rust which allows flexibility in usage.

Bug: 373864033
Change-Id: I3d72aa8ecd11151235d3dd387b313c9d0309d4a6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5953710
Auto-Submit: Mohannad Farrag <aymanm@google.com>
Commit-Queue: David Benjamin <davidben@chromium.org>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: danakj <danakj@chromium.org>
Reviewed-by: danakj <danakj@chromium.org>
Reviewed-by: David Benjamin <davidben@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1374672}
This commit is contained in:
Mohannad Farrag
2024-10-28 16:38:21 +00:00
committed by Chromium LUCI CQ
parent 3e6695f6b0
commit 63ce6fc17e
16 changed files with 504 additions and 321 deletions
base
build/rust
bindings.rsrust_bindgen.gnirust_bindgen_generator.gnirust_target.gni
tests
bindgen_cpp_test
bindgen_cpp_test_with_cpp_linkage
bindgen_static_fns_test
bindgen_test
third_party
boringssl
crabbyavif

@ -2490,12 +2490,6 @@ rust_static_library("rust_logger") {
crate_root = "logging/rust_logger.rs"
cxx_bindings = [ "logging/rust_logger.rs" ]
_bindgen_output = get_target_outputs(":rust_log_bindgen")
inputs = _bindgen_output
rustenv =
[ "RUST_LOG_INTEGRATION_BINDGEN_RS_FILE=" +
rebase_path(_bindgen_output[0], get_path_info(crate_root, "dir")) ]
}
if (is_linux || is_chromeos) {

@ -6,12 +6,12 @@ use log::Level::{Debug, Error, Info, Trace, Warn};
use log::{LevelFilter, Metadata, Record};
use std::ffi::CString;
mod rust_log_integration {
include!(env!("RUST_LOG_INTEGRATION_BINDGEN_RS_FILE"));
chromium::import! {
"//base:rust_log_bindgen";
}
use rust_log_integration::root::logging::internal::print_rust_log;
use rust_log_integration::root::logging::internal::{
use rust_log_bindgen::logging::internal::print_rust_log;
use rust_log_bindgen::logging::internal::{
RustLogSeverity_DEBUG, RustLogSeverity_ERROR, RustLogSeverity_INFO, RustLogSeverity_TRACE,
RustLogSeverity_WARNING,
};

16
build/rust/bindings.rs Normal file

@ -0,0 +1,16 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#[allow(dead_code)]
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
mod bindings {
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
#[cfg(cpp)]
pub use bindings::root::*;
#[cfg(not(cpp))]
pub use bindings::*;

@ -5,6 +5,7 @@
import("//build/config/clang/clang.gni")
import("//build/config/rust.gni")
import("//build/config/sysroot.gni")
import("//build/rust/rust_bindgen_generator.gni")
import("//build/rust/rust_static_library.gni")
if (is_win) {
@ -27,9 +28,8 @@ if (host_os == "win") {
# Template to build Rust/C bindings with bindgen.
#
# This template expands to an action that generates the Rust side of the
# bindings. Add it as a dependency and then incorporate
# `get_target_outputs(target_name)[0]` into your Rust crate.
# This template expands to a rust_static_library that exports the
# bindings generated from bindgen at the root of the library.
#
# Parameters:
#
@ -59,269 +59,58 @@ if (host_os == "win") {
# build. Additionally, `get_target_outputs` will return both the Rust file and
# a generated C file, but callers can rely on the Rust file being first.
#
# Rust targets depending on the output must `include!` the generated file, which
# can be done as follows. Export `BINDGEN_RS_FILE` in the Rust GN target:
# ```
# bindgen_output = get_target_outputs(":<rust_bindgen_target>")
# inputs = bindgen_output
# rustenv = [
# "BINDGEN_RS_FILE=" +
# rebase_path(bindgen_output[0], get_path_info(crate_root, "dir"))
# ]
# ```
# And then include the generated header file in the Rust library:
# ```
# #[allow(dead_code)]
# #[allow(non_upper_case_globals)]
# #[allow(non_camel_case_types)]
# #[allow(non_snake_case)]
# mod ffi {
# include!(env!("BINDGEN_RS_FILE"));
# }
# ```
# If using `cpp = true`, consider adding this to the bottom of the `ffi` module,
# below the `include!`:
# ```
# pub use root::*;
# ```
#
# For a small, self-contained example please see:
# * C header: //build/rust/tests/bindgen_test
# * C++ header: //build/rust/tests/bindgen_cpp_test
template("rust_bindgen") {
assert(defined(invoker.header),
"Must specify the C/C++ header file to make bindings for.")
_wrap_static_fns = defined(invoker.wrap_static_fns) && invoker.wrap_static_fns
# "_generator" will be added to the rust_bindgen_generator target.
_rust_bindgen_generator_name = target_name + "_generator"
_wrap_static_fns = false
if (defined(invoker.wrap_static_fns) && invoker.wrap_static_fns) {
_wrap_static_fns = true
}
rust_bindgen_generator(_rust_bindgen_generator_name) {
forward_variables_from(invoker,
"*",
[
"library_name",
"output_name",
] + TESTONLY_AND_VISIBILITY)
if (!defined(invoker.cpp)) {
_cpp = false
} else {
_cpp = invoker.cpp
# This will allow the rust_static_library to depend on the `rust_bindgen_generator`
# through visibility.
library_name = target_name
# We know the library that is going to consume this rust_bindgen and we're sure
# that only a single bindgen is there. So rename the bindings to avoid passing
# envflags.
# envflags are usually problematic for Cronet as Soong does not support it (b/181221467).
output_name = "bindings"
}
_bindgen_target_name = target_name
action(_bindgen_target_name) {
# bindgen relies on knowing the {{defines}} and {{include_dirs}} required
# to build the C++ headers which it's parsing. These are passed to the
# script's args and are populated using deps and configs.
rust_static_library(target_name) {
forward_variables_from(invoker,
TESTONLY_AND_VISIBILITY + [
"configs",
"deps",
"public_configs",
"public_deps",
"crate_name",
"cpp",
])
sources = [ invoker.header ]
if (!defined(configs)) {
configs = []
}
# Several important compiler flags come from default_compiler_configs
configs += default_compiler_configs
output_dir = "$target_gen_dir"
out_gen_rs = "$output_dir/${target_name}.rs"
script = rebase_path("//build/rust/run_bindgen.py")
inputs = [
_bindgen_path,
"//build/action_helpers.py",
"//build/gn_helpers.py",
"//build/rust/filter_clang_args.py",
]
depfile = "$target_out_dir/${target_name}.d"
outputs = [ out_gen_rs ]
args = [
"--exe",
rebase_path(_bindgen_path, root_build_dir),
"--header",
rebase_path(invoker.header, root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
"--output",
rebase_path(out_gen_rs, root_build_dir),
"--libclang-path",
rebase_path(_libclang_path, root_build_dir),
]
crate_root = "//build/rust/bindings.rs"
sources = [ crate_root ]
bindgen_deps = [ ":$_rust_bindgen_generator_name" ]
allow_unsafe = true
if (_wrap_static_fns) {
if (_cpp) {
out_gen_c = "$output_dir/${target_name}.cc"
} else {
out_gen_c = "$output_dir/${target_name}.c"
}
outputs += [ out_gen_c ]
args += [
"--wrap-static-fns",
rebase_path(out_gen_c, root_build_dir),
# Add a dependency on the static_fns library for simplicity if
# it's declared.
deps = [ ":${_rust_bindgen_generator_name}_static_fns" ]
}
if (defined(cpp) && cpp) {
# This cfg is used to control the bindings public export.
rustflags = [
"--cfg",
"cpp",
]
}
if (is_linux) {
# Linux clang, and clang libs, use a shared libstdc++, which we must
# point to.
args += [
"--ld-library-path",
rebase_path(clang_base_path + "/lib", root_build_dir),
]
}
args += [ "--bindgen-flags" ]
if (defined(invoker.bindgen_flags)) {
foreach(flag, invoker.bindgen_flags) {
args += [ flag ]
}
}
if (_cpp) {
args += [ "enable-cxx-namespaces" ]
}
# Everything below is passed through to libclang.
args += [ "--" ]
if (_cpp) {
args += [
"-x",
"c++",
]
}
args += [
"{{defines}}",
"{{include_dirs}}",
"{{cflags}}",
]
if (_cpp) {
args += [ "{{cflags_cc}}" ]
} else {
args += [ "{{cflags_c}}" ]
}
# libclang will run the system `clang` to find the "resource dir" which it
# places before the directory specified in `-isysroot`.
# https://github.com/llvm/llvm-project/blob/699e0bed4bfead826e210025bf33e5a1997c018b/clang/lib/Tooling/Tooling.cpp#L499-L510
#
# This means include files are pulled from the wrong place if the `clang`
# says the wrong thing. We point it to our clang's resource dir which will
# make it behave consistently with our other command line flags and allows
# system headers to be found.
clang_resource_dir =
rebase_path(clang_base_path + "/lib/clang/" + clang_version,
root_build_dir)
args += [
"-resource-dir",
clang_resource_dir,
]
# The `--sysroot` flag is not working as expected and gets ignored (we don't
# fully understand why, see b/328510249). But we add `-isystem` to point at
# the headers in the sysroot which are otherwise not found.
if (sysroot != "") {
if (is_win) {
args +=
[ "-I" + rebase_path(sysroot + "/usr/include/", root_build_dir) ]
} else {
args += [
"-isystem",
rebase_path(sysroot + "/usr/include/", root_build_dir),
]
}
}
if (is_win) {
# On Windows we fall back to using system headers from a sysroot from
# depot_tools. This is negotiated by python scripts and the result is
# available in //build/toolchain/win/win_toolchain_data.gni. From there
# we get the `include_flags_imsvc` which point to the system headers.
if (host_cpu == "x86") {
win_toolchain_data = win_toolchain_data_x86
} else if (host_cpu == "x64") {
win_toolchain_data = win_toolchain_data_x64
} else if (host_cpu == "arm64") {
win_toolchain_data = win_toolchain_data_arm64
} else {
error("Unsupported host_cpu, add it to win_toolchain_data.gni")
}
args += win_toolchain_data.include_flags_imsvc_list
}
# Passes C comments through as rustdoc attributes.
if (is_win) {
args += [ "/clang:-fparse-all-comments" ]
} else {
args += [ "-fparse-all-comments" ]
}
# Default configs include "-fvisibility=hidden", and for some reason this
# causes bindgen not to emit function bindings. Override it.
if (!is_win) {
args += [ "-fvisibility=default" ]
}
if (is_win) {
# We pass MSVC style flags to clang on Windows, and libclang needs to be
# told explicitly to accept them.
args += [ "--driver-mode=cl" ]
# On Windows, libclang adds arguments that it then fails to understand.
# -fno-spell-checking
# -fallow-editor-placeholders
# These should not cause bindgen to fail.
args += [ "-Wno-unknown-argument" ]
# C++ mode makes bindgen pass /TP to libclang (to parse as C++) which
# then libclang says is unused.
args += [ "-Wno-unused-command-line-argument" ]
# Replace these two arguments with a version that clang-cl can parse.
args += [
"/clang:-fno-spell-checking",
"/clang:-fallow-editor-placeholders",
]
}
if (is_cfi) {
# LLVM searches for a default CFI ignorelist at (exactly)
# $(cwd)/lib/clang/$(llvm_version)/share/cfi_ignorelist.txt
# Even if we provide a custom -fsanitize-ignorelist, the absence
# of this default file will cause a fatal error. clang finds
# it within third_party/llvm-build, but for bindgen our cwd
# is the $out_dir. We _could_ create this file at the right
# location within the outdir using a "copy" target, but as
# we don't actually generate code within bindgen, the easier
# option is to tell bindgen to ignore all CFI ignorelists.
args += [ "-fno-sanitize-ignorelist" ]
}
}
if (_wrap_static_fns) {
source_set("${target_name}_static_fns") {
forward_variables_from(invoker,
TESTONLY_AND_VISIBILITY + [
"deps",
"configs",
"public_configs",
"public_deps",
])
bindgen_output = get_target_outputs(":${_bindgen_target_name}")
if (!defined(deps)) {
deps = []
}
deps += [ ":${_bindgen_target_name}" ]
if (_cpp) {
sources = filter_include(bindgen_output, [ "*.cc" ])
} else {
sources = filter_include(bindgen_output, [ "*.c" ])
}
# bindgen generates a C file whose include is relative to the directory it
# runs from.
include_dirs = [ root_build_dir ]
}
}
}

@ -0,0 +1,361 @@
# 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/rust_static_library.gni")
if (is_win) {
import("//build/toolchain/win/win_toolchain_data.gni")
}
_bindgen_path = "${rust_bindgen_root}/bin/bindgen"
if (host_os == "win") {
_bindgen_path = "${_bindgen_path}.exe"
}
# On Windows, the libclang.dll is beside the bindgen.exe, otherwise it is in
# ../lib.
_libclang_path = rust_bindgen_root
if (host_os == "win") {
_libclang_path += "/bin"
} else {
_libclang_path += "/lib"
}
# Template to build Rust/C bindings with bindgen.
#
# If you're developing first-party code then consider using `rust_bindgen`
# instead of `rust_bindgen_generator` to simplify your build targets.
#
# This template expands to an action that generates the Rust side of the
# bindings. Add it as a dependency through `bindgen_deps` on your
# rust_target then incorporate it into your library through
#
# mod bindings {
# include!(concat!(env!("OUT_DIR"), "/{rust_bindgen_generator_target_name}.rs"));
# }
#
# Parameters:
#
# header:
# The .h file to generate bindings for.
#
# deps: (optional)
# C targets on which the headers depend in order to build successfully.
#
# configs: (optional)
# C compilation targets determine the correct list of -D and -I flags based
# on their dependencies and any configs applied. The same applies here. Set
# any configs here as if this were a C target.
#
# cpp: (optional)
# Use C++ mode to consume the header instead of C mode (the default).
#
# bindgen_flags: (optional)
# The additional bindgen flags which are passed to the executable. A `--` will
# be prepended to each flag. So use `bindgen_flags = [ "foo" ]` to pass
# `--foo` to bindgen.
#
# wrap_static_fns: (optional)
# If set to true, enables binding `static` and `static inline` functions in
# the header. Setting this causes the template to emit a source_set target
# named "${target_name}_static_fns", which must be incorporated into the
# build. Additionally, `get_target_outputs` will return both the Rust file and
# a generated C file, but callers can rely on the Rust file being first.
template("rust_bindgen_generator") {
assert(defined(invoker.header),
"Must specify the C/C++ header file to make bindings for.")
_wrap_static_fns = defined(invoker.wrap_static_fns) && invoker.wrap_static_fns
if (!defined(invoker.cpp)) {
_cpp = false
} else {
_cpp = invoker.cpp
}
# This is only created if the bindgen has wrap_static_fns to true
_static_fn_target_name = target_name + "_static_fns"
if (defined(invoker.library_name)) {
_library_name = invoker.library_name
}
_bindgen_target_name = target_name
action(target_name) {
# bindgen relies on knowing the {{defines}} and {{include_dirs}} required
# to build the C++ headers which it's parsing. These are passed to the
# script's args and are populated using deps and configs.
forward_variables_from(invoker,
TESTONLY_AND_VISIBILITY + [
"configs",
"deps",
"public_configs",
"public_deps",
"output_name",
])
sources = [ invoker.header ]
if (!defined(configs)) {
configs = []
}
# Get rid of the visibility, the user should not control visibility.
# We have to do it that way otherwise we might get "visibility not used"
# errors.
visibility = []
# This should only be allowed to be used by third_party code.
# First-party code should use `rust_bindgen` template.
# We're intentionally not allowing visibility to be forwarded
# to prevent people from doing visibility = ["*"] which will
# allow a rust_bindgen_generator to be used by 1P folks.
visibility = [ "//third_party/*" ]
if (defined(_library_name)) {
# Allow both the rust target and the copy target to be able to depend on
# the rust_bindgen_generator.
visibility += [
# This can be deleted once boringssl and crabbyavif switch
# rust_bindgen_generator targets from `deps` to `bindgen_deps`.
":${_library_name}",
":${_library_name}_${_bindgen_target_name}_copy",
]
}
if (_wrap_static_fns) {
visibility += [ ":$_static_fn_target_name" ]
}
# Several important compiler flags come from default_compiler_configs
configs += default_compiler_configs
output_dir = "$target_gen_dir"
if (!defined(output_name)) {
output_name = target_name
}
output_file = "$output_dir/${output_name}.rs"
script = rebase_path("//build/rust/run_bindgen.py")
inputs = [
_bindgen_path,
"//build/action_helpers.py",
"//build/gn_helpers.py",
"//build/rust/filter_clang_args.py",
]
depfile = "$target_out_dir/${target_name}.d"
outputs = [ output_file ]
args = [
"--exe",
rebase_path(_bindgen_path, root_build_dir),
"--header",
rebase_path(invoker.header, root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
"--output",
rebase_path(output_file, root_build_dir),
"--libclang-path",
rebase_path(_libclang_path, root_build_dir),
]
if (_wrap_static_fns) {
if (_cpp) {
out_gen_c = "$output_dir/${target_name}.cc"
} else {
out_gen_c = "$output_dir/${target_name}.c"
}
outputs += [ out_gen_c ]
args += [
"--wrap-static-fns",
rebase_path(out_gen_c, root_build_dir),
]
}
if (is_linux) {
# Linux clang, and clang libs, use a shared libstdc++, which we must
# point to.
args += [
"--ld-library-path",
rebase_path(clang_base_path + "/lib", root_build_dir),
]
}
args += [ "--bindgen-flags" ]
if (defined(invoker.bindgen_flags)) {
foreach(flag, invoker.bindgen_flags) {
args += [ flag ]
}
}
if (_cpp) {
args += [ "enable-cxx-namespaces" ]
}
# Everything below is passed through to libclang.
args += [ "--" ]
if (_cpp) {
args += [
"-x",
"c++",
]
}
args += [
"{{defines}}",
"{{include_dirs}}",
"{{cflags}}",
]
if (_cpp) {
args += [ "{{cflags_cc}}" ]
} else {
args += [ "{{cflags_c}}" ]
}
# libclang will run the system `clang` to find the "resource dir" which it
# places before the directory specified in `-isysroot`.
# https://github.com/llvm/llvm-project/blob/699e0bed4bfead826e210025bf33e5a1997c018b/clang/lib/Tooling/Tooling.cpp#L499-L510
#
# This means include files are pulled from the wrong place if the `clang`
# says the wrong thing. We point it to our clang's resource dir which will
# make it behave consistently with our other command line flags and allows
# system headers to be found.
clang_resource_dir =
rebase_path(clang_base_path + "/lib/clang/" + clang_version,
root_build_dir)
args += [
"-resource-dir",
clang_resource_dir,
]
# The `--sysroot` flag is not working as expected and gets ignored (we don't
# fully understand why, see b/328510249). But we add `-isystem` to point at
# the headers in the sysroot which are otherwise not found.
if (sysroot != "") {
if (is_win) {
args +=
[ "-I" + rebase_path(sysroot + "/usr/include/", root_build_dir) ]
} else {
args += [
"-isystem",
rebase_path(sysroot + "/usr/include/", root_build_dir),
]
}
}
if (is_win) {
# On Windows we fall back to using system headers from a sysroot from
# depot_tools. This is negotiated by python scripts and the result is
# available in //build/toolchain/win/win_toolchain_data.gni. From there
# we get the `include_flags_imsvc` which point to the system headers.
if (host_cpu == "x86") {
win_toolchain_data = win_toolchain_data_x86
} else if (host_cpu == "x64") {
win_toolchain_data = win_toolchain_data_x64
} else if (host_cpu == "arm64") {
win_toolchain_data = win_toolchain_data_arm64
} else {
error("Unsupported host_cpu, add it to win_toolchain_data.gni")
}
args += win_toolchain_data.include_flags_imsvc_list
}
# Passes C comments through as rustdoc attributes.
if (is_win) {
args += [ "/clang:-fparse-all-comments" ]
} else {
args += [ "-fparse-all-comments" ]
}
# Default configs include "-fvisibility=hidden", and for some reason this
# causes bindgen not to emit function bindings. Override it.
if (!is_win) {
args += [ "-fvisibility=default" ]
}
if (is_win) {
# We pass MSVC style flags to clang on Windows, and libclang needs to be
# told explicitly to accept them.
args += [ "--driver-mode=cl" ]
# On Windows, libclang adds arguments that it then fails to understand.
# -fno-spell-checking
# -fallow-editor-placeholders
# These should not cause bindgen to fail.
args += [ "-Wno-unknown-argument" ]
# C++ mode makes bindgen pass /TP to libclang (to parse as C++) which
# then libclang says is unused.
args += [ "-Wno-unused-command-line-argument" ]
# Replace these two arguments with a version that clang-cl can parse.
args += [
"/clang:-fno-spell-checking",
"/clang:-fallow-editor-placeholders",
]
}
if (is_cfi) {
# LLVM searches for a default CFI ignorelist at (exactly)
# $(cwd)/lib/clang/$(llvm_version)/share/cfi_ignorelist.txt
# Even if we provide a custom -fsanitize-ignorelist, the absence
# of this default file will cause a fatal error. clang finds
# it within third_party/llvm-build, but for bindgen our cwd
# is the $out_dir. We _could_ create this file at the right
# location within the outdir using a "copy" target, but as
# we don't actually generate code within bindgen, the easier
# option is to tell bindgen to ignore all CFI ignorelists.
args += [ "-fno-sanitize-ignorelist" ]
}
if (!defined(_library_name)) {
not_needed([ _bindgen_target_name ])
}
}
if (_wrap_static_fns) {
source_set(_static_fn_target_name) {
forward_variables_from(invoker,
TESTONLY_AND_VISIBILITY + [
"deps",
"configs",
"public_configs",
"public_deps",
])
bindgen_output = get_target_outputs(":${_bindgen_target_name}")
if (!defined(deps)) {
deps = []
}
deps += [ ":${_bindgen_target_name}" ]
if (_cpp) {
sources = filter_include(bindgen_output, [ "*.cc" ])
} else {
sources = filter_include(bindgen_output, [ "*.c" ])
}
# bindgen generates a C file whose include is relative to the directory it
# runs from.
include_dirs = [ root_build_dir ]
# Get rid of the visibility, the user should not control visibility.
# We have to do it that way otherwise we might get "visibility not used"
# errors.
visibility = []
if (defined(_library_name)) {
# Allow both the rust target declared through `rust_bindgen` to depend
# on this library.
visibility = [ ":${_library_name}" ]
} else {
# This should only be allowed to be used by third_party code.
# First-party code should use `rust_bindgen` template.
# We're intentionally not allowing visibility to be forwarded
# to prevent people from doing visibility = ["*"] which will
# allow a rust_bindgen_generator to be used by 1P folks.
visibility = [ "//third_party/*" ]
}
}
} else {
not_needed([ _static_fn_target_name ])
}
}

@ -17,6 +17,10 @@ if (enable_rust_cxx) {
# understand some handy variables such as "edition" and "features" and also to
# build any associated unit tests.
#
# `bindgen_deps` field exists only for 3P cargo sys crates that uses
# `rust_bindgen_generator` templates. For 1P code, `rust_bindgen` should
# be used and should go directly in the `deps` field.
#
# Normally, you should not use this directly. Use either
# - cargo_crate.gni - for 3p crates only
# - rust_static_library.gni - for 1p Rust code
@ -163,6 +167,34 @@ template("rust_target") {
if (defined(invoker.deps)) {
_deps += invoker.deps
}
if (defined(invoker.bindgen_deps)) {
_bindgen_inputs = []
# This iteration assumes that no targets have the same name which is
# very rare to happen and if it does. An error will be thrown as we
# try to create two targets with the same name, the error might not
# be descriptive enough so maybe adding a check action would be better.
foreach(bindgen_dep, invoker.bindgen_deps) {
_copy_target_name =
target_name + "_" + get_label_info(bindgen_dep, "name") + "_copy"
copy(_copy_target_name) {
_bindgen_output_files = get_target_outputs(bindgen_dep)
# `rust_bindgen_generator` promises that the first output file is always .rs.
sources = [ _bindgen_output_files[0] ]
outputs = [ "$_env_out_dir/{{source_name_part}}.rs" ]
deps = [ bindgen_dep ]
}
# The bindgen-generated rs files are inputs to this library for the library
# to `include!` them.
# The output of the copy action is always a single file so just copy everything.
_bindgen_inputs += get_target_outputs(":$_copy_target_name")
# Depend on the bindgen generation to make the above `_bindgen_inputs`.
_deps += [ ":$_copy_target_name" ]
}
}
_public_deps = []
if (defined(invoker.public_deps)) {
_public_deps += invoker.public_deps
@ -406,6 +438,14 @@ template("rust_target") {
sources += [ _crate_root ]
}
if (!defined(inputs)) {
inputs = []
}
if (defined(_bindgen_inputs)) {
inputs += _bindgen_inputs
}
if (!defined(output_name)) {
# Note that file names of libraries must start with the crate name in
# order for the compiler to find transitive dependencies in the

@ -27,9 +27,4 @@ rust_executable("bindgen_cpp_test") {
crate_root = "main.rs"
allow_unsafe = true # Needed for FFI.
bindgen_output = get_target_outputs(":cpp_lib_bindgen")
inputs = bindgen_output
rustenv = [ "BINDGEN_RS_FILE=" +
rebase_path(bindgen_output[0], get_path_info(crate_root, "dir")) ]
}

@ -2,17 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#[allow(dead_code)]
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
mod ffi {
include!(env!("BINDGEN_RS_FILE"));
pub use root::*;
chromium::import! {
"//build/rust/tests/bindgen_cpp_test:cpp_lib_bindgen";
}
pub fn main() {
let from_cpp = unsafe { ffi::functions::normal_fn(ffi::functions::kNumber) };
let from_cpp =
unsafe { cpp_lib_bindgen::functions::normal_fn(cpp_lib_bindgen::functions::kNumber) };
println!("2 == {from_cpp}");
assert_eq!(2, from_cpp);
}

@ -27,11 +27,6 @@ rust_static_library("rust_lib") {
crate_root = "lib.rs"
allow_unsafe = true # Needed for FFI.
bindgen_output = get_target_outputs(":cpp_lib_bindgen")
inputs = bindgen_output
rustenv = [ "BINDGEN_RS_FILE=" +
rebase_path(bindgen_output[0], get_path_info(crate_root, "dir")) ]
}
executable("bindgen_cpp_test_with_cpp_linkage") {

@ -2,18 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#[allow(dead_code)]
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
mod ffi {
include!(env!("BINDGEN_RS_FILE"));
pub use root::*;
chromium::import! {
"//build/rust/tests/bindgen_cpp_test_with_cpp_linkage:cpp_lib_bindgen";
}
#[no_mangle]
pub fn rust_main() {
let from_cpp = unsafe { ffi::functions::normal_fn(ffi::functions::kNumber) };
let from_cpp =
unsafe { cpp_lib_bindgen::functions::normal_fn(cpp_lib_bindgen::functions::kNumber) };
println!("2 == {from_cpp}");
assert_eq!(2, from_cpp);
}

@ -29,16 +29,10 @@ rust_static_library("bindgen_static_fns_test_lib") {
deps = [
":c_lib",
":c_lib_bindgen",
":c_lib_bindgen_static_fns",
]
sources = [ "src/lib.rs" ]
build_native_rust_unit_tests = true
crate_root = "src/lib.rs"
bindgen_output = get_target_outputs(":c_lib_bindgen")
inputs = bindgen_output
rustenv = [ "BINDGEN_RS_FILE=" +
rebase_path(bindgen_output[0], get_path_info(crate_root, "dir")) ]
}
rust_executable("bindgen_static_fns_test") {

@ -2,16 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
mod c_ffi {
#![allow(dead_code)]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
include!(env!("BINDGEN_RS_FILE"));
chromium::import! {
"//build/rust/tests/bindgen_static_fns_test:c_lib_bindgen";
}
pub fn mul_three_numbers_in_c(a: u32, b: u32, c: u32) -> u32 {
unsafe { c_ffi::mul_three_numbers(a, b, c) }
unsafe { c_lib_bindgen::mul_three_numbers(a, b, c) }
}
#[cfg(test)]

@ -35,11 +35,6 @@ rust_static_library("bindgen_test_lib") {
sources = [ "src/lib.rs" ]
build_native_rust_unit_tests = true
crate_root = "src/lib.rs"
bindgen_output = get_target_outputs(":c_lib_bindgen")
inputs = bindgen_output
rustenv = [ "BINDGEN_RS_FILE=" +
rebase_path(bindgen_output[0], get_path_info(crate_root, "dir")) ]
}
rust_executable("bindgen_test") {

@ -2,16 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#[allow(dead_code)]
#[allow(non_snake_case)]
#[allow(non_camel_case_types)]
#[allow(non_upper_case_globals)]
mod c_ffi {
include!(env!("BINDGEN_RS_FILE"));
chromium::import! {
"//build/rust/tests/bindgen_test:c_lib_bindgen";
}
pub fn add_two_numbers_in_c(a: u32, b: u32) -> u32 {
unsafe { c_ffi::add_two_numbers(a, b) }
unsafe { c_lib_bindgen::add_two_numbers(a, b) }
}
#[cfg(test)]

@ -12,7 +12,7 @@ import("src/gen/sources.gni")
if (enable_rust) {
import("//build/rust/cargo_crate.gni")
import("//build/rust/rust_bindgen.gni")
import("//build/rust/rust_bindgen_generator.gni")
}
# Config for us and everybody else depending on BoringSSL.
@ -49,7 +49,8 @@ all_sources = bcm_internal_headers + bcm_sources + crypto_internal_headers +
all_headers = crypto_headers + ssl_headers + pki_headers + pki_internal_headers
if (enable_rust) {
rust_bindgen("raw_bssl_sys_bindings") {
rust_bindgen_generator("raw_bssl_sys_bindings") {
output_name = "bindgen"
header = "src/rust/bssl-sys/wrapper.h"
deps = [ ":boringssl" ]
bindgen_flags = [
@ -78,13 +79,18 @@ if (enable_rust) {
edition = "2021"
deps = [
":boringssl",
":raw_bssl_sys_bindings",
":raw_bssl_sys_bindings", # Delete once the source code has changed.
":raw_bssl_sys_bindings_static_fns",
]
visibility = [
":*", # private, should only be exposed through bssl_crypto
]
bindgen_deps = [ ":raw_bssl_sys_bindings" ]
# This is no longer necessary and can be deleted once the source
# code is changed to use `OUT_DIR` always.
bindgen_output = get_target_outputs(":raw_bssl_sys_bindings")
inputs = bindgen_output
rustenv =

@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/rust/rust_bindgen.gni")
import("//build/rust/rust_bindgen_generator.gni")
import("//build/rust/rust_static_library.gni")
rust_bindgen("crabbyavif_dav1d_bindings") {
rust_bindgen_generator("crabbyavif_dav1d_bindings") {
header = "src/sys/dav1d-sys/wrapper.h"
deps = [ "//third_party/dav1d:dav1d_headers" ]
configs = [ "//third_party/dav1d:dav1d_config" ]
@ -33,8 +33,15 @@ rust_static_library("crabbyavif_dav1d_sys") {
sources = [ "src/sys/dav1d-sys/src/lib.rs" ]
deps = [ ":crabbyavif_dav1d_bindings" ]
deps = [
":crabbyavif_dav1d_bindings", # Kept for backward compatibility, delete
# once the source code has changed
]
bindgen_deps = [ ":crabbyavif_dav1d_bindings" ]
# This is no longer necessary and can be deleted once the source
# code is changed to use `OUT_DIR` always.
_bindgen_output = get_target_outputs(":crabbyavif_dav1d_bindings")
inputs = _bindgen_output
rustenv =
@ -42,7 +49,7 @@ rust_static_library("crabbyavif_dav1d_sys") {
rebase_path(_bindgen_output[0], get_path_info(crate_root, "dir")) ]
}
rust_bindgen("crabbyavif_libyuv_bindings") {
rust_bindgen_generator("crabbyavif_libyuv_bindings") {
header = "src/sys/libyuv-sys/wrapper.h"
configs = [ "//third_party/libyuv:libyuv_config" ]
bindgen_flags = [
@ -117,8 +124,15 @@ rust_static_library("crabbyavif_libyuv_sys") {
sources = [ "src/sys/libyuv-sys/src/lib.rs" ]
deps = [ ":crabbyavif_libyuv_bindings" ]
deps = [
":crabbyavif_libyuv_bindings", # Kept for backward compatibility, delete
# once the source code has changed
]
bindgen_deps = [ ":crabbyavif_libyuv_bindings" ]
# This is no longer necessary and can be deleted once the source
# code is changed to use `OUT_DIR` always.
_bindgen_output = get_target_outputs(":crabbyavif_libyuv_bindings")
inputs = _bindgen_output
rustenv =