سیستم ساخت از تولید اتصالات bindgen از طریق نوع ماژول rust_bindgen پشتیبانی میکند. Bindgen اتصالات Rust FFI را برای کتابخانههای C فراهم میکند (با پشتیبانی محدود از C++ که نیاز به تنظیم ویژگی cppstd دارد).
کاربرد اولیه rust_bindgen
آنچه در ادامه میآید مثالی از نحوه تعریف ماژولی است که از bindgen استفاده میکند و نحوه استفاده از آن ماژول به عنوان یک جعبه (crate). اگر نیاز به استفاده از bindgen bindings از طریق یک ماکروی include!() دارید، مانند کد خارجی، به صفحه Source Generators مراجعه کنید.
مثال کتابخانه C برای فراخوانی از Rust
یک کتابخانه 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 توصیه میکند که یک ماژول تست برای این تستها تعریف کنید و تستها به عنوان بخشی از مجموعه تستهای معمول پروژه شما اجرا شوند.
یک فایل باینری آزمایشی برای این موارد را میتوان به راحتی با تعریف یک ماژول rust_test در 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",
}
قابلیت مشاهده و ارتباط
متغیرهای تولید شده معمولاً بسیار کوچک هستند، زیرا شامل تعاریف نوع، امضای توابع و ثابتهای مرتبط هستند. در نتیجه، پیوند پویای این کتابخانهها عموماً بیفایده است. ما پیوند پویا را برای این ماژولها غیرفعال کردهایم تا استفاده از آنها از طریق rustlibs به طور خودکار یک نوع ایستا را انتخاب کند.
به طور پیشفرض، ماژولهای rust_bindgen دارای ویژگی visibility با مقدار [":__subpackages__"] هستند که فقط به ماژولهای موجود در همان فایل Android.bp یا ماژولهای زیر آن در سلسله مراتب دایرکتوری اجازه میدهد تا آن را ببینند. این دو هدف را دنبال میکند:
- این امر استفاده از اتصالات خام C را در جای دیگر درخت منع میکند.
- با ترکیبی از پیوند استاتیک و دینامیک، از مشکلات پیوند الماسی جلوگیری میکند.
معمولاً، شما باید یک کتابخانه بستهبندی امن در اطراف ماژول تولید شدهای که اضافه کردهاید، در همان درخت دایرکتوری به عنوان اتصالات، که برای استفاده سایر توسعهدهندگان در نظر گرفته شده است، فراهم کنید. اگر این برای مورد استفاده شما کار نمیکند، میتوانید بستههای اضافی را به قابلیت مشاهده اضافه کنید. هنگام افزودن محدودههای مشاهده اضافی، لطفاً مراقب باشید که دو محدوده اضافه نکنید که ممکن است در آینده به یک فرآیند مرتبط شوند، زیرا ممکن است این پیوند برقرار نشود.
ویژگیهای قابل توجه rust_bindgen
ویژگیهای تعریفشده در زیر علاوه بر ویژگیهای مشترک مهمی هستند که برای همه ماژولها اعمال میشوند. این ویژگیها یا بهطور ویژه برای ماژولهای Rust bindgen مهم هستند، یا رفتار منحصربهفردی را که مختص نوع ماژول rust_bindgen است، نشان میدهند.
ساقه، نام، نام جعبه
rust_bindgen انواع کتابخانه تولید میکند، بنابراین آنها الزامات یکسانی را با ماژولهای rust_library برای ویژگیهای stem ، name و crate_name به اشتراک میگذارند. برای مرجع به ویژگیهای کتابخانهای برجسته Rust مراجعه کنید.
wrapper_src
این مسیر نسبی به یک فایل هدر wrapper است که شامل هدرهای مورد نیاز برای این اتصالات است. پسوند فایل نحوه تفسیر هدر را تعیین میکند و مشخص میکند که از کدام پرچم -std به طور پیشفرض استفاده شود. فرض میشود که این یک هدر C است، مگر اینکه پسوند آن .hh یا .hpp باشد. اگر هدر C++ شما باید پسوند دیگری داشته باشد، ویژگی cpp_std را طوری تنظیم کنید که رفتار پیشفرض را که فرض میکند فایل یک فایل C است، نادیده بگیرد.
منبع_stem
این نام فایل منبع تولید شده است. این فیلد باید تعریف شود، حتی اگر از اتصالات به عنوان جعبه استفاده میکنید، زیرا ویژگی stem فقط نام فایل خروجی را برای انواع کتابخانه تولید شده کنترل میکند. اگر یک ماژول به چندین مولد منبع (مانند bindgen و protobuf ) به عنوان منبع وابسته است نه به عنوان جعبه از طریق rustlibs ، باید مطمئن شوید که همه مولدهای منبع که وابستگیهای آن ماژول هستند، مقادیر منحصر به فرد source_stem دارند. ماژولهای وابسته، منابع را از همه وابستگیهای SourceProvider که در srcs تعریف شدهاند، در یک دایرکتوری OUT_DIR مشترک کپی میکنند، بنابراین تداخل در source_stem منجر به رونویسی فایلهای منبع تولید شده در دایرکتوری OUT_DIR میشود.
سی_استد
این یک رشته است که نشان میدهد از کدام نسخه استاندارد 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 مورد نیاز برای تفسیر صحیح هدرها را ارائه میدهد.
custom_bindgen
برای موارد استفاده پیشرفته، bindgen میتواند به عنوان یک کتابخانه استفاده شود و یک API ارائه دهد که میتواند به عنوان بخشی از یک فایل باینری سفارشی Rust دستکاری شود. فیلد custom_bindgen نام ماژول یک ماژول rust_binary_host را میگیرد که از API bindgen به جای فایل باینری معمولی 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: ["."],
}