构建系统支持通过rust_bindgen
模块类型生成 bindgen 绑定。 Bindgen 为 C 库提供 Rust FFI 绑定(具有一些有限的 C++ 支持,这需要设置cppstd
属性)。
基本的 rust_bindgen 用法
下面是一个示例,说明如何定义使用 bindgen 的模块,以及如何将该模块用作 crate。如果您需要通过include!()
宏使用 bindgen 绑定,例如外部代码,请参阅Source Generators页面。
从 Rust 调用的示例 C 库
下面是一个示例 C 库,它定义了用于 Rust 的结构和函数。
external/rust/libbuzz/libbuzz.h
typedef struct foo {
int x;
} foo;
void fizz(int i, foo* cs);
external/rust/libbuzz/libbuzz.c
#include <stdio.h>
#include "libbuzz.h"
void fizz(int i, foo* my_foo){
printf("hello from c! i = %i, my_foo->x = %i\n", i, my_foo->x);
}
定义一个 rust_bindgen 模块
定义一个包装头文件external/rust/libbuzz/libbuzz_wrapper.h
,其中包括所有相关的头文件:
// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"
将Android.bp
文件定义为external/rust/libbuzz/Android.bp
:
cc_library {
name: "libbuzz",
srcs: ["libbuzz.c"],
}
rust_bindgen {
name: "libbuzz_bindgen",
// Crate name that's used to generate the rust_library variants.
crate_name: "buzz_bindgen",
// Path to the wrapper source file.
wrapper_src: "libbuzz_wrapper.h",
// 'source_stem' controls the output filename.
// This is the filename that's used in an include! macro.
//
// In this case, we just use "bindings", which produces
// "bindings.rs".
source_stem: "bindings",
// Bindgen-specific flags and options to customize the bindings.
// See the bindgen manual for more information.
bindgen_flags: ["--verbose"],
// Clang flags to be used when generating the bindings.
cflags: ["-DSOME_FLAG"],
// Shared, static, and header libraries which export the necessary
// include directories must be specified.
//
// These libraries will also be included in the crate if static,
// or propagated to dependents if shared.
// static_libs: ["libbuzz"]
// header_libs: ["libbuzz"]
shared_libs: ["libbuzz"],
}
要了解有关使用 bindgen 标志的更多信息,请参阅自定义生成的绑定的 bindgen 手册部分。
如果您使用本节将rust_bindgen
模块定义为使用include!()
宏的先决条件,请返回源生成器页面上的先决条件。如果没有,请继续下一节。
使用绑定作为板条箱
使用以下内容创建external/rust/hello_bindgen/Android.bp
:
rust_binary {
name: "hello_bindgen",
srcs: ["main.rs"],
// Add the rust_bindgen module as if it were a rust_library dependency.
rustlibs: ["libbuzz_bindgen"],
}
使用以下内容创建external/rust/hello_bindgen/src/main.rs
:
//! Example crate for testing bindgen bindings
fn main() {
let mut x = buzz_bindgen::foo { x: 2 };
unsafe { buzz_bindgen::fizz(1, &mut x as *mut buzz_bindgen::foo) }
}
最后,调用m hello_bindgen
来构建二进制文件。
测试 Bindgen 绑定
Bindgen 绑定通常包含许多生成的布局测试,以防止内存布局不匹配。 AOSP 建议您为这些测试定义一个测试模块,并将这些测试作为项目正常测试套件的一部分运行。
通过在external/rust/hello_bindgen/Android.bp
中定义一个rust_test
模块,可以轻松生成这些测试二进制文件:
rust_test {
name: "bindings_test",
srcs: [
":libbuzz_bindgen",
],
crate_name: "buzz_bindings_test",
test_suites: ["general-tests"],
auto_gen_config: true,
// Be sure to disable lints as the generated source
// is not guaranteed to be lint-free.
clippy_lints: "none",
lints: "none",
}
值得注意的 rust_bindgen 属性
下面定义的属性是对适用于所有模块的重要公共属性的补充。这些要么对 Rust bindgen 模块特别重要,要么表现出特定于rust_bindgen
模块类型的独特行为。
茎,名称,箱子名称
rust_bindgen
生成库变体,因此它们与rust_library
模块对stem
、 name
和crate_name
属性的要求相同。请参阅值得注意的 Rust 库属性以供参考。
wrapper_src
这是包含这些绑定所需的头文件的包装头文件的相对路径。文件扩展名确定如何解释标头并确定默认使用哪个-std
标志。除非扩展名是 .hh 或.hh
,否则假定为 C 标.hpp
。如果您的 C++ 标头必须具有其他扩展名,请设置cpp_std
属性以覆盖假定文件是 C 文件的默认行为。
源干
这是生成的源文件的文件名。即使您将绑定用作 crate,也必须定义此字段,因为stem
属性仅控制生成的库变体的输出文件名。如果一个模块依赖多个源生成器(例如bindgen
和protobuf
)作为源而不是通过rustlibs
作为 crates,则必须确保作为该模块依赖项的所有源生成器都具有唯一的source_stem
值。依赖模块将srcs
中定义的所有SourceProvider
依赖项中的源复制到一个公共的OUT_DIR
目录中,因此source_stem
中的冲突将导致生成的源文件在OUT_DIR
目录中被覆盖。
c_std
这是一个字符串,表示要使用的 C 标准版本。下面列出了有效值:
- 特定版本,例如“gnu11”
- 由构建系统在
build/soong/cc/config/global.go
中定义的“实验”值,当它们可用时,可能会使用像 C++1z 这样的草稿版本。 - "default" 或 " " 都使用构建系统默认值。
- 由构建系统在
如果设置了此项,则忽略文件扩展名并假定标头是 C 标头。这不能与cpp_std
同时设置。
cpp_std
cpp_std
是一个字符串,表示要使用哪个 C 标准版本。有效值:
特定版本,例如“gnu++11”
- 由构建系统在
build/soong/cc/config/global.go
中定义的“实验”值,当它们可用时,可能会使用像 C++1z 这样的草稿版本。 - “default”或“”都是构建系统的默认值。
- 由构建系统在
如果设置了此项,则忽略文件扩展名,并且假定标头是 C++ 标头。这不能与c_std
同时设置。
标志
cflags
提供正确解释标头所需的 Clang 标志的字符串列表。
custom_bindgen
对于高级用例,bindgen 可以用作库,提供可以作为自定义 Rust 二进制文件的一部分进行操作的 API。 custom_bindgen
字段采用rust_binary_host
模块的模块名称,该模块使用 bindgen API 而不是普通的bindgen
二进制文件。
此自定义二进制文件必须以与bindgen
类似的方式期待参数,例如“ my_bindgen [flags] wrapper_header.h -o [output\_path] -- [clang flags]
”。其中大部分是由bindgen
库本身处理的。要查看此用法的示例,请访问external/rust/crates/libsqlite3-sys/android/build.rs 。
此外,完整的库属性集可用于控制库的编译,尽管这些属性很少需要定义或更改。