Bindgen 绑定模块

构建系统支持通过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模块对stemnamecrate_name属性的要求相同。请参阅值得注意的 Rust 库属性以供参考。

wrapper_src

这是包含这些绑定所需的头文件的包装头文件的相对路径。文件扩展名确定如何解释标头并确定默认使用哪个-std标志。除非扩展名是 .hh 或.hh ,否则假定为 C 标.hpp 。如果您的 C++ 标头必须具有其他扩展名,请设置cpp_std属性以覆盖假定文件是 C 文件的默认行为。

源干

这是生成的源文件的文件名。即使您将绑定用作 crate,也必须定义此字段,因为stem属性仅控制生成的库变体的输出文件名。如果一个模块依赖多个源生成器(例如bindgenprotobuf )作为源而不是通过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

此外,完整的库属性集可用于控制库的编译,尽管这些属性很少需要定义或更改。