يتيح نظام التصميم إنشاء روابط bindgen من خلال نوع الوحدة rust_bindgen
. توفّر Bindgen روابط Rust FFI لمكتبات C (مع بعض
الدعم المحدود للغة C++، والذي يتطلّب ضبط السمة cppstd
).
الاستخدام الأساسي لـ rust_bindgen
في ما يلي مثال على كيفية تحديد وحدة تستخدم bindgen، وكيفية استخدام هذه الوحدة كحزمة. إذا كنت بحاجة إلى استخدام روابط bindgen من خلال
وحدة ماكرو include!()
، مثل الرمز الخارجي، راجِع صفحة
مولّدات المصدر.
مثال على مكتبة 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
.
stem, name, crate_name
تنتج rust_bindgen
صيغ مكتبة، لذا فهي تشترك في المتطلبات نفسها مع وحدات rust_library
لسمات stem
وname
وcrate_name
. يمكنك الاطّلاع على خصائص مكتبة Rust البارزة كمرجع.
wrapper_src
هذا هو المسار النسبي إلى ملف عنوان برنامج تضمين يتضمّن العناوين المطلوبة لعمليات الربط هذه. يحدّد امتداد الملف كيفية تفسير العنوان، كما يحدّد علامة -std
التي سيتم استخدامها تلقائيًا. من المفترَض أن يكون هذا العنوان C
ما لم تكن الإضافة .hh
أو .hpp
. إذا كان يجب أن يتضمّن عنوان C++ بعض الامتدادات الأخرى، اضبط السمة cpp_std
لتجاوز السلوك التلقائي الذي يفترض أنّ الملف هو ملف C.
source_stem
هذا هو اسم ملف ملف المصدر الذي تم إنشاؤه. يجب تحديد هذا الحقل حتى إذا كنت تستخدم عمليات الربط كحزمة، لأنّ السمة stem
تتحكّم فقط في اسم ملف الإخراج لخيارات المكتبة التي تم إنشاؤها.
إذا كانت الوحدة النمطية تعتمد على عدة مولدات مصدر (مثل bindgen
وprotobuf
) كمصدر بدلاً من الحِزم من خلال rustlibs
، يجب التأكّد من أنّ جميع مولدات المصدر التي تعتمد عليها هذه الوحدة النمطية تتضمّن قيم source_stem
فريدة. تنسخ الوحدات التابعة المصادر من جميع التبعيات SourceProvider
المحدّدة في srcs
إلى دليل OUT_DIR
مشترك، وبالتالي ستؤدي التعارضات في source_stem
إلى استبدال ملفات المصدر التي تم إنشاؤها في الدليل OUT_DIR
.
c_std
هذه سلسلة تمثّل إصدار C-standard الذي سيتم استخدامه. في ما يلي القيم الصالحة:
- إصدار معيّن، مثل
"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 كمكتبة توفّر واجهة برمجة تطبيقات يمكن التعامل معها كجزء من ملف ثنائي مخصّص مكتوب بلغة Rust. يأخذ الحقل custom_bindgen
اسم وحدة rust_binary_host
التي تستخدم واجهة برمجة التطبيقات 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: ["."],
}