建構系統支援透過 rust_bindgen
模組類型產生 bindgen 繫結。Bindgen 提供 C 程式庫的 Rust FFI 繫結 (支援部分 C++,但需要設定 cppstd
屬性)。
rust_bindgen 基本用法
以下範例說明如何定義使用 bindgen 的模組,以及如何將該模組做為 Crate 使用。如需透過 include!()
巨集使用 bindgen 繫結 (例如用於外部程式碼),請參閱「來源產生器」頁面。
可從 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!()
巨集的必要條件,請返回「來源產生器」頁面的「必要條件」。如果沒有,請繼續下一個部分。
將繫結當做 Crate 使用
建立 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",
}
可見度和連結
產生的繫結通常很小,因為其中包含型別定義、函式簽章和相關常數。因此,動態連結這些程式庫通常會浪費資源。我們已停用這些模組的動態連結,因此透過 rustlibs
使用這些模組時,系統會自動選取靜態變體。
根據預設,rust_bindgen
模組的 visibility
屬性為 [":__subpackages__"]
,因此只有位於同一 Android.bp
檔案或目錄階層中該檔案下方的模組,才能看到該模組。這有兩個目的:
- 這項做法可避免在樹狀結構的其他位置使用原始 C 繫結。
- 可避免靜態和動態連結混用時出現菱形連結問題。
通常,您應在繫結所在的相同目錄樹中,提供所加入產生模組的安全包裝函式庫,供其他開發人員使用。如果這不符合您的用途,可以將其他套件新增至瀏覽權限。新增其他可見度範圍時,請注意不要新增日後可能會連結至相同程序的兩個範圍,否則可能會無法連結。
rust_bindgen 的重要屬性
除了適用於所有模組的重要通用屬性外,您也可以定義下列屬性。這些屬性對於 Rust 繫結模組特別重要,或是展現 rust_bindgen
模組類型特有的行為。
幹、名稱、crate_name
rust_bindgen
會產生程式庫變體,因此與 stem
、name
和 crate_name
屬性的 rust_library
模組共用相同需求。如需參考資料,請參閱「值得注意的 Rust 程式庫屬性」。
wrapper_src
這是封裝函式庫標頭檔案的相對路徑,其中包含這些繫結所需的標頭。檔案副檔名會決定如何解讀標頭,以及預設要使用哪個 -std
標記。除非擴充功能是 .hh
或 .hpp
,否則這會假設為 C 標頭 unless。如果 C++ 標頭必須使用其他副檔名,請設定 cpp_std
屬性,覆寫預設行為 (假設檔案為 C 檔案)。
source_stem
這是產生的來源檔案名稱。即使您將繫結做為 Crate 使用,也必須定義這個欄位,因為 stem
屬性只會控管所產生程式庫變體的輸出檔案名稱。如果模組依附於多個來源產生器 (例如 bindgen
和 protobuf
),而非透過 rustlibs
做為 Crate,請務必確保該模組的所有依附來源產生器都有不重複的 source_stem
值。依附元件模組會將 srcs
中定義的所有 SourceProvider
依附元件來源複製到共用的 OUT_DIR
目錄,因此 source_stem
中的衝突會導致產生的來源檔案在 OUT_DIR
目錄中遭到覆寫。
c_std
這是代表要使用的 C 標準版本的字串。有效值如下:
- 特定版本,例如
"gnu11"
。 - ,這是建構系統在
build/soong/cc/config/global.go
中定義的值,可能會使用C++1z 等草案版本 (如有)。"experimental"
- 未設定或
""
,表示應使用建構系統預設值。
如果設定此值,系統會忽略副檔名,並假設標頭為 C 標頭。這項設定無法與 cpp_std
同時設定。
cpp_std
cpp_std
是代表要使用的 C 標準版本的字串。有效值:
- 特定版本,例如
"gnu++11"
- ,這是建構系統在
build/soong/cc/config/global.go
中定義的值,可能會使用C++1z 等草案版本 (如有)。"experimental"
- 未設定或
""
,表示應使用建構系統預設值。
如果設定此選項,系統會忽略副檔名,並假設標頭為 C++ 標頭。這項設定無法與 c_std
同時設定。
cflags
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。
此外,您也可以使用整組程式庫屬性來控制程式庫的編譯作業,但這些屬性很少需要定義或變更。
handle_static_inline 和 static_inline_library
這兩個屬性應一併使用,可為靜態內嵌函式產生包裝函式,並納入匯出的 bindgen 繫結。
如要使用這些函式,請設定 handle_static_inline: true
並將 static_inline_library
設為對應的 cc_library_static
,定義 rust_bindgen
模組做為來源輸入內容。
使用範例:
rust_bindgen {
name: "libbindgen",
wrapper_src: "src/any.h",
crate_name: "bindgen",
stem: "libbindgen",
source_stem: "bindings",
// Produce bindings for static inline fucntions
handle_static_inline: true,
static_inline_library: "libbindgen_staticfns"
}
cc_library_static {
name: "libbindgen_staticfns",
// This is the rust_bindgen module defined above
srcs: [":libbindgen"],
// The include path to the header file in the generated c file is
// relative to build top.
include_dirs: ["."],
}