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

الجذعية، الاسم، اسم الصندوق

يُنتج rust_bindgen متغيرات للمكتبة، لذا فهي تشترك في نفس المتطلبات مع وحدات rust_library الخاصة بخصائص stem name واسم crate_name . راجع خصائص مكتبة الصدأ الملحوظ كمرجع.

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 عندما تكون متاحة.
  • Unset أو "" ، مما يشير إلى أنه يجب استخدام الإعداد الافتراضي لنظام البناء.

إذا تم تعيين هذا، فسيتم تجاهل امتداد الملف ويفترض أن الرأس هو رأس C. لا يمكن ضبط هذا في نفس الوقت مع cpp_std .

cpp_std

cpp_std عبارة عن سلسلة تمثل إصدار C القياسي الذي سيتم استخدامه. القيم الصالحة:

  • إصدار محدد، مثل "gnu++11"
  • "experimental" ، وهي قيمة يحددها نظام البناء في build/soong/cc/config/global.go ، قد تستخدم إصدارات أولية مثل C++1z عندما تكون متاحة.
  • Unset أو "" ، مما يشير إلى أنه يجب استخدام الإعداد الافتراضي لنظام البناء.

إذا تم تعيين هذا، فسيتم تجاهل امتداد الملف ويفترض أن الرأس هو رأس C++. لا يمكن ضبط هذا في نفس الوقت مع c_std .

com.cflags

يوفر cflags قائمة سلاسل من أعلام Clang المطلوبة لتفسير الرؤوس بشكل صحيح.

custom_bindgen

بالنسبة لحالات الاستخدام المتقدمة، يمكن استخدام bindgen كمكتبة، مما يوفر واجهة برمجة التطبيقات (API) التي يمكن معالجتها كجزء من ثنائي 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 .

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