يتيح نظام الإنشاء إنشاء عمليات ربط 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: ["."],
    }