建置系統支援透過rust_bindgen模組類型產生 bindgen 綁定。 Bindgen 提供 Rust FFI 到 C 庫的綁定(具有一些有限的 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!()巨集的先決條件,請返回來源產生器頁面上的先決條件。如果沒有,請繼續下一部分。

使用綁定作為箱子

使用以下內容建立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模組具有[":__subpackages__"]visibility屬性,該屬性僅允許同一Android.bp檔案中的模組或目錄層次結構中位於該檔案下方的模組看到它。這有兩個目的:

  • 它不鼓勵在樹的其他地方使用原始 C 綁定。
  • 它透過靜態和動態連結的混合避免了鑽石連結問題。

通常,您應該為您添加到與綁定相同的目錄樹中的生成模組提供一個安全的包裝器庫,供其他開發人員使用。如果這不適用於您的用例,您可以將其他套件添加到可見性中。當新增其他可見性範圍時,請注意不要新增兩個將來可能連結到同一進程的範圍,因為這可能會連結失敗。

值得注意的 rust_bindgen 屬性

下面定義的屬性是適用於所有模組的重要公共屬性的補充。這些要么對 Rust bindgen 模組特別重要,要么表現出特定於rust_bindgen模組類型的獨特行為。

莖、名稱、板條箱名稱

rust_bindgen產生庫變體,因此它們與rust_library模組對stemnamecrate_name屬性具有相同的要求。請參閱值得注意的 Rust 庫屬性以供參考。

包裝來源

這是包裝器頭檔的相對路徑,其中包含這些綁定所需的頭。檔案副檔名決定如何解釋標頭並確定預設使用哪個-std標誌。除非副檔名是.hh.hpp ,否則假定它是 C 標頭。如果您的 C++ 標頭必須具有其他副檔名,請設定cpp_std屬性以覆寫假定該檔案是 C 檔案的預設行為。

源_莖

這是產生的來源檔案的檔案名稱。即使您將綁定用作包,也必須定義此字段,因為stem屬性僅控制生成的庫變體的輸出檔名。如果一個模組依賴多個來源產生器(例如bindgenprotobuf )作為來源而不是透過rustlibs作為套件,則必須確保作為該模組依賴項的所有來源產生器都具有唯一的source_stem值。依賴模組將srcs中定義的所有SourceProvider相依性中的原始碼複製到公共OUT_DIR目錄,因此source_stem中的衝突將導致產生的來源檔案在OUT_DIR目錄中被覆寫。

c_std

這是一個表示要使用哪個 C 標準版本的字串。下面列出了有效值:

  • 特定版本,例如"gnu11"
  • "experimental"是由build/soong/cc/config/global.go中的建置系統定義的值,可以使用C++1z 等草稿版本(當它們可用時)。
  • 取消設定或"" ,表示應使用建置系統預設值。

如果設定了此選項,則忽略檔案副檔名,並假定標頭是 C 標頭。這不能與cpp_std同時設定。

cpp_std

cpp_std是一個字串,表示要使用哪個 C 標準版本。有效值:

  • 特定版本,例如"gnu++11"
  • "experimental"是由build/soong/cc/config/global.go中的建置系統定義的值,可以使用C++1z 等草稿版本(當它們可用時)。
  • 取消設定或"" ,表示應使用建置系統預設值。

如果設定了此選項,則忽略檔案副檔名,並假定標頭是 C++ 標頭。這不能與c_std同時設定。

cflags

cflags提供正確解釋標頭所需的 Clang 標誌的字串清單。

自訂綁定生成器

對於進階用例,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

此外,全套函式庫屬性可用於控制函式庫的編譯,儘管這些屬性很少需要定義或變更。