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

بالإضافة إلى ذلك، تتوفّر المجموعة الكاملة من سمات المكتبة للتحكّم في compiling المكتبة، على الرغم من أنّه نادرًا ما تحتاج هذه السمات إلى التحديد أو التغيير.

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: ["."],
    }