Hệ thống xây dựng hỗ trợ tạo liên kết bindgen thông qua loại mô-đun rust_bindgen
. Bindgen cung cấp các liên kết FFI Rust cho thư viện C (với một số tính năng hỗ trợ C++ bị hạn chế, yêu cầu đặ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 bindgen và cách sử dụng mô-đun đó làm một vùng chứa. Nếu bạn cần sử dụng các liên kết bindgen thông qua một macro include!()
, chẳng hạn như cho mã bên ngoài, hãy xem trang 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 mọi 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.bp
là 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"],
}
Để tìm hiểu thêm về cách sử dụng cờ liên kết, hãy xem phần hướng dẫn về liên kết trên trang 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
với 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
Các liên kết Bindgen thường chứa một số kiểm thử bố cục được tạo để ngăn chặn tình trạng không khớp bố cục bộ nhớ. AOSP đề xuất bạn nên có một mô-đun kiểm thử được xác định cho các kiểm thử này và các kiểm thử nên chạy như một phần 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",
}
Chế độ 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à các 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
là [":__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 thuộc tính này. Điều này phục vụ hai mục đích:
- Bạn không nên sử dụng các liên kết C thô ở 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 khác vào mức độ hiển thị. Khi thêm các phạm vi hiển thị bổ sung, vui lòng lưu ý không thêm hai phạm vi có thể được liên kết vào cùng một quy trình trong tương lai, vì việc 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 bên dưới là ngoài Các thuộc tính chung 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
.
stem, name, crate_name
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
, name
và crate_name
. Hãy xem phần Các thuộc tính thư viện Rust đáng chú ý để tham khảo.
wrapper_src
Đây là đường dẫn tương đối đến tệp tiêu đề trình bao bọc có tiêu đề cần thiết cho các liên kết này. Đuôi tệp này xác định cách diễn giải tiêu đề và xác định cờ -std
nào cần 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ó đuôi 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.
gốc_nguồn
Đây là tên tệp cho tệp nguồn được tạo. Bạn phải xác định trường này, ngay cả khi bạn đang sử dụng các liên kết dưới dạng một vùng chứa, vì thuộc tính stem
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ư bindgen
và protobuf
) dưới dạng nguồn thay vì dưới dạng thùng thông qua rustlibs
, thì bạn phải đảm bảo rằng tất cả trình tạo nguồn là phần phụ thuộc của mô-đun đó đều có giá trị source_stem
duy nhất. Các mô-đun phụ thuộc 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 đã 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. Dưới đây là các giá trị hợp lệ:
- 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 trongbuild/soong/cc/config/global.go
, có thể sử dụng các phiên bản nháp như C++1z khi có.- Huỷ đặt hoặc
""
để cho biết phải 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 cpp_std
.
cpp_std
cpp_std
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ệ:
- 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 trongbuild/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, thì đuôi tệp sẽ bị bỏ qua và tiêu đề được giả định là tiêu đề C++. Bạn không thể đặt thuộc tính này cùng lúc với c_std
.
cflags
cflags
cung cấp danh sách chuỗi gồm các cờ Clang cần thiết để diễn giải chính xác tiêu đề.
custom_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 cách tương tự như bindgen
, chẳng hạn như
$ my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]
Hầu hết việc này đều do thư viện bindgen
xử lý. Để xem ví dụ về cách sử dụng này, hãy truy cập vào external/rust/crates/libsqlite3-sys/android/build.rs.
Ngoài ra, bạn có thể tập hợp đầy đủ các thuộc tính thư viện để kiểm soát quá trình biên dịch thư viện, mặc dù các thuộc tính này hiếm khi cần 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 mô-đun này, hãy đặt handle_static_inline: true
và đặt static_inline_library
thành
cc_library_static
tương ứng. Thao tác này sẽ xác định mô-đun rust_bindgen
là
dữ liệu đầu vào 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: ["."],
}