يتيح نظام الإنشاء إنشاء عمليات ربط 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، راجع قسم دليل الربط حول تخصيص الروابط التي يتم إنشاؤها.
إذا استخدَمت هذا القسم لتعريف وحدة 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 الأوّلية في أي مكان آخر في الشجرة.
- ويتجنّب هذا الأسلوب مشاكل الربط على شكل ماسة من خلال مزيج من الربط الثابت والديناميكي.
وعادةً ما يكون عليك توفير مكتبة ملفّ لفّ آمن حول الوحدة المُنشأة التي أضفتها في شجرة الدليل نفسها التي تتضمّن عمليات الربط المخصّصة ل use المطوّرين الآخرين. إذا لم تنجح هذه الطريقة في حلّ مشكلة حالة الاستخدام، يمكنك إضافة حِزم إضافية إلى مستوى العرض. عند إضافة نطاقات رؤية إضافية، يُرجى الحرص على عدم إضافة نطاقَين قد يتم ربطهما في العملية نفسها في المستقبل، لأنّ ذلك قد يؤدي إلى عدم الربط.
سمات 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.
جذع_المصدر
تمثّل هذه السمة اسم الملف للملف المصدر الذي تم إنشاؤه. يجب
تحديد هذا الحقل، حتى إذا كنت تستخدم عمليات الربط كمجموعة، لأنّ السمة 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.
بالإضافة إلى ذلك، تتوفّر المجموعة الكاملة من سمات المكتبة للتحكّم في compiling المكتبة، على الرغم من أنّه نادرًا ما تحتاج هذه السمات إلى التحديد أو التغيير.
Hand_static_inline وstatic_inline_library
تم تصميم هاتين السمتَين معًا والسماح بإنتاج برامج تضمين للدوال المضمّنة الثابتة التي يمكن تضمينها في عمليات ربط الروابط التي يتم تصديرها.
لاستخدامها، اضبط 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: ["."],
}