Hệ thống xây dựng hỗ trợ việc tạo các liên kết bindgen thông qua loại mô-đun rust_bindgen. Bindgen cung cấp liên kết Rust FFI với các thư viện C (với một số khả năng hỗ trợ C++ có giới hạn, yêu cầu phải đặt thuộc tính cppstd).

Cách sử dụng rust_bindgen cơ bản

Sau đây là ví dụ về cách xác định một mô-đun sử dụng trình ràng buộc, và cách sử dụng mô-đun đó làm hộp. Nếu bạn cần sử dụng liên kết ràng buộc thông qua macro include!(), chẳng hạn như đối với mã bên ngoài, hãy xem Trình tạo nguồn .

Thư viện C mẫu để gọi từ Rust

Sau đây là ví dụ về thư viện C xác định một cấu trúc và hàm để sử dụng trong 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);
}

Xác định mô-đun rust_bindgen

Xác định tiêu đề trình bao bọc external/rust/libbuzz/libbuzz_wrapper.h, trong đó bao gồm tất cả tiêu đề có liên quan:

// Include headers that are required for generating bindings in a wrapper header.
#include "libbuzz.h"

Xác định tệp Android.bpexternal/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"],
}

Để tìm hiểu thêm về cách sử dụng cờ bindgen, hãy xem phần hướng dẫn về bindgen về Tuỳ chỉnh liên kết được tạo.

Nếu bạn đã sử dụng phần này để xác định mô-đun rust_bindgen làm điều kiện tiên quyết để sử dụng macro include!(), hãy quay lại phần Điều kiện tiên quyết trên trang Trình tạo nguồn. Nếu không, hãy chuyển sang các phần tiếp theo.

Sử dụng liên kết dưới dạng một vùng chứa

Tạo external/rust/hello_bindgen/Android.bp với nội dung sau:

rust_binary {
   name: "hello_bindgen",
   srcs: ["main.rs"],

   // Add the rust_bindgen module as if it were a rust_library dependency.
   rustlibs: ["libbuzz_bindgen"],
}

Tạo external/rust/hello_bindgen/src/main.rs có nội dung sau:

//! 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) }
}

Cuối cùng, hãy gọi m hello_bindgen để tạo tệp nhị phân.

Kiểm thử các liên kết Bindgen

Liên kết liên kết thường chứa một số bài kiểm thử bố cục được tạo để ngăn chặn bố cục bộ nhớ không khớp. AOSP đề xuất bạn xác định một mô-đun kiểm thử cho các kiểm thử này và các kiểm thử này sẽ chạy trong bộ kiểm thử thông thường của dự án.

Bạn có thể dễ dàng tạo tệp nhị phân kiểm thử cho các tệp này bằng cách xác định mô-đun rust_test trong external/rust/hello_bindgen/Android.bp:

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",
}

Khả năng hiển thị và mối liên kết

Các liên kết được tạo thường rất nhỏ, vì chúng bao gồm các định nghĩa loại, chữ ký hàm và hằng số liên quan. Do đó, việc liên kết động các thư viện này thường là lãng phí. Chúng tôi đã tắt tính năng liên kết động cho các mô-đun này để việc sử dụng các mô-đun đó thông qua rustlibs sẽ tự động chọn một biến thể tĩnh.

Theo mặc định, các mô-đun rust_bindgen có thuộc tính visibility[":__subpackages__"]. Thuộc tính này sẽ chỉ cho phép các mô-đun trong cùng tệp Android.bp hoặc các mô-đun bên dưới tệp đó trong hệ phân cấp thư mục xem được thuộc tính này. Việc này phục vụ hai mục đích:

  • Không khuyến khích sử dụng liên kết C thô ở những nơi khác trong cây.
  • Phương thức này giúp tránh các vấn đề liên kết kim cương bằng cách kết hợp liên kết tĩnh và động.

Thông thường, bạn nên cung cấp một thư viện trình bao bọc an toàn xung quanh mô-đun đã tạo mà bạn đã thêm vào cùng một cây thư mục với các liên kết dành cho các nhà phát triển khác sử dụng. Nếu cách này không phù hợp với trường hợp sử dụng của bạn, bạn có thể thêm các gói bổ sung để visibility. Khi thêm các phạm vi hiển thị khác, xin lưu ý rằng bạn không thêm hai phạm vi có thể được liên kết với cùng một quy trình trong tương lai, vì điều này có thể không liên kết được.

Các thuộc tính rust_bindgen đáng chú ý

Các thuộc tính được xác định dưới đây bổ sung cho Các thuộc tính phổ biến quan trọng áp dụng cho tất cả các mô-đun. Các thuộc tính này đặc biệt quan trọng đối với các mô-đun Rust bindgen hoặc thể hiện hành vi riêng biệt dành riêng cho loại mô-đun rust_bindgen.

gốc, tên, tên_ thùng

rust_bindgen tạo các biến thể thư viện, vì vậy, các biến thể này có cùng yêu cầu với mô-đun rust_library cho các thuộc tính stem, namecrate_name. Xem Các thuộc tính đáng chú ý của thư viện Rust để tham khảo.

giá trị wrap_src

Đây là đường dẫn tương đối đến tệp tiêu đề trình bao bọc có tiêu đề bắt buộc cho các liên kết này. Đuôi tệp xác định cách diễn giải tiêu đề và xác định cờ -std nào sẽ sử dụng theo mặc định. Đây được giả định là tiêu đề C trừ phi phần mở rộng là .hh hoặc .hpp. Nếu tiêu đề C++ của bạn phải có một số tiện ích khác, hãy đặt thuộc tính cpp_std để ghi đè hành vi mặc định giả định tệp là tệp C.

source_stem

Đây là tên tệp cho tệp nguồn đã tạo. Trường này phải được xác định, ngay cả khi bạn đang sử dụng các liên kết làm thùng, vì stem thuộc tính này chỉ kiểm soát tên tệp đầu ra cho các biến thể thư viện đã tạo. Nếu một mô-đun phụ thuộc vào nhiều trình tạo nguồn (chẳng hạn như bindgenprotobuf) dưới dạng nguồn thay vì dưới dạng thùng thông qua rustlibs, bạn phải đảm bảo rằng tất cả các trình tạo nguồn là các phần phụ thuộc của mô-đun đó có giá trị source_stem duy nhất. Các mô-đun phụ thuộc sẽ sao chép nguồn từ tất cả các phần phụ thuộc SourceProvider được xác định trong srcs vào một thư mục OUT_DIR chung, vì vậy, các xung đột trong source_stem sẽ dẫn đến việc các tệp nguồn được tạo bị ghi đè trong thư mục OUT_DIR.

c_std

Đây là một chuỗi đại diện cho phiên bản tiêu chuẩn C cần sử dụng. Giá trị hợp lệ được liệt kê bên dưới:

  • Một phiên bản cụ thể, chẳng hạn như "gnu11".
  • "experimental" là một giá trị do hệ thống xây dựng xác định trong build/soong/cc/config/global.go, có thể sử dụng các phiên bản nháp như C++1z khi có.
  • Không đặt hoặc "", cho biết bạn nên sử dụng chế độ mặc định của hệ thống xây dựng.

Nếu bạn đặt chính sách này, đuôi tệp sẽ bị bỏ qua và tiêu đề được giả định là là tiêu đề C. Bạn không thể đặt thuộc tính này cùng lúc với cpp_std.

cpp_std

cpp_std là một chuỗi đại diện cho phiên bản chuẩn C sẽ được sử dụng. Giá trị hợp lệ:

  • Một phiên bản cụ thể, chẳng hạn như "gnu++11"
  • "experimental" là một giá trị do hệ thống xây dựng xác định trong build/soong/cc/config/global.go, có thể sử dụng các phiên bản nháp như C++1z khi có.
  • Không đặt hoặc "", cho biết bạn nên sử dụng chế độ mặc định của hệ thống xây dựng.

Nếu bạn đặt thuộc tính này, đuôi tệp sẽ bị bỏ qua và tiêu đề được giả định là tiêu đề C++. Không thể thiết lập thuộc tính này cùng lúc với c_std.

cflags

cflags cung cấp danh sách chuỗi các cờ Clang cần thiết để diễn giải chính xác các tiêu đề.

tuỳ_chỉnh_bindgen

Đối với các trường hợp sử dụng nâng cao, bạn có thể sử dụng bindgen làm thư viện, cung cấp một API có thể được thao tác như một phần của tệp nhị phân Rust tuỳ chỉnh. Trường custom_bindgen lấy tên mô-đun của mô-đun rust_binary_host, sử dụng API bindgen thay vì tệp nhị phân bindgen thông thường.

Tệp nhị phân tuỳ chỉnh này phải dự kiến các đối số theo kiểu tương tự như bindgen, chẳng hạn như dưới dạng

$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]

Hầu hết các thao tác này đều do chính thư viện bindgen xử lý. Để xem ví dụ về hãy truy cập vào external/rust/crates/libsqlite3-sys/android/build.rs.

Ngoài ra, bạn có thể sử dụng toàn bộ bộ thuộc tính thư viện để kiểm soát việc biên dịch thư viện, mặc dù các thuộc tính này hiếm khi cần được xác định hoặc thay đổi.

handle_static_inline và static_inline_library

Hai thuộc tính này được dùng cùng nhau và cho phép tạo trình bao bọc cho các hàm cùng dòng tĩnh có thể được đưa vào các liên kết bindgen đã xuất.

Để sử dụng các thành phần này, hãy đặt handle_static_inline: true và đặt static_inline_library thành một cc_library_static tương ứng xác định mô-đun rust_bindgen là đầu vào của nguồn.

Ví dụ về cách sử dụng:

    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: ["."],
    }