Hệ thống bản dựng hỗ trợ tạo các 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 các thư viện C (với một số tính năng hỗ trợ C++ hạn chế, yêu cầu bạn 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 bindgen và cách sử dụng mô-đun đó làm một crate. Nếu bạn cần sử dụng các liên kết bindgen thông qua macro include!()
, chẳng hạn như đối với mã bên ngoài, hãy xem trang Trình tạo nguồn.
Ví dụ về thư viện C để 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
, bao gồm tất cả cá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.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ờ bindgen, hãy xem phần hướng dẫn bindgen về Tuỳ chỉnh các liên kết đã tạo.
Nếu bạn đã sử dụng phần này để xác định một 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 các liên kết làm thùng chứa
Tạo external/rust/hello_bindgen/Android.bp
bằng 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
bằng 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 sự không khớp bố cục bộ nhớ. 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ử đó chạy trong bộ kiểm thử thông thường của dự án.
Bạn có thể dễ dàng tạo một tệp nhị phân kiểm thử cho các tệp này bằng cách xác định một 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à 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 kiểu, chữ ký hàm và các hằng số liên quan. Do đó, việc liên kết các thư viện này một cách linh động thường rất 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 này 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ệ thống phân cấp thư mục nhìn thấy. Việc này có 2 mục đích:
- Điều này ngăn chặn việc sử dụng các liên kết C thô ở những nơi khác trong cây.
- Việc này giúp tránh các vấn đề về liên kết kim cương khi 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 dưới dạng các liên kết dành cho những 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, thì bạn có thể thêm các gói khác vào chế độ hiển thị. Khi thêm các phạm vi hiển thị bổ sung, vui lòng lưu ý rằng bạn 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ì điều này có thể không liên kết được.
Các thuộc tính đáng chú ý của rust_bindgen
Ngoài các thuộc tính được xác định bên dưới, còn có Các thuộc tính chung quan trọng áp dụng cho tất cả các mô-đun. Đây là những mô-đun đặc biệt quan trọng đối với các mô-đun Rust bindgen hoặc có 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 ra 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 các mô-đun rust_library
cho các thuộc tính stem
, name
và crate_name
. Hãy xem Các thuộc tính đáng chú ý của thư viện Rust để tham khảo.
wrapper_src
Đây là đường dẫn tương đối đến một tệp tiêu đề trình bao bọc bao gồm các tiêu đề bắt buộc cho những liên kết này. Phần mở rộng của tệp xác định cách diễn giải tiêu đề và xác định cờ -std
nào sẽ được dùng theo mặc định. Đây được giả định là tiêu đề C trừ phi tiện ích là .hh
hoặc .hpp
. Nếu tiêu đề C++ của bạn phải có một số đuôi khác, hãy đặt thuộc tính cpp_std
để ghi đè hành vi mặc định giả định rằng tệp là tệp C.
source_stem
Đây là tên tệp của tệp nguồn được tạo. Bạn phải xác định trường này, ngay cả khi đang sử dụng các liên kết dưới dạng một thù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
) làm nguồn thay vì làm các thùng thông qua rustlibs
, 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ó các giá trị source_stem
riêng biệt. Các mô-đun phụ thuộc sao chép các 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, do đó, 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 thể hiện phiên bản tiêu chuẩn C sẽ sử dụng. Các giá trị hợp lệ được liệt kê dưới đây:
- Một phiên bản cụ thể, chẳng hạn như
"gnu11"
. "experimental"
(là giá trị do hệ thống bản 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ó sẵn.- Chưa đặ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 giá trị 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 chế độ này cùng lúc với cpp_std
.
cpp_std
cpp_std
là một chuỗi thể hiện phiên bản tiêu chuẩn C sẽ 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à giá trị do hệ thống bản 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ó sẵn.- Chưa đặ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 giá trị này, đuôi tệp sẽ bị bỏ qua và tiêu đề được giả định là tiêu đề C++. Bạn không thể đặt chế độ 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 các tiêu đề.
custom_bindgen
Đối với các trường hợp sử dụng nâng cao, bạn có thể 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ột 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 yêu cầu 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 các thao tác này đều do chính 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ể sử dụng toàn bộ các thuộc tính của thư viện để kiểm soát quá trình biên dịch thư viện, mặc dù hiếm khi cần xác định hoặc thay đổi các thuộc tính này.
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 cc_library_static
tương ứng. cc_library_static
này sẽ xác định mô-đun rust_bindgen
làm nguồn đầu vào.
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: ["."],
}