يتيح نظام التصميم إنشاء روابط 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 القياسي الذي سيتم استخدامه. في ما يلي القيم الصالحة:
- إصدار معيّن، مثل
"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: ["."],
}