سیستم ساخت از تولید اتصالات bindgen از طریق نوع ماژول rust_bindgen پشتیبانی می‌کند. Bindgen اتصالات Rust FFI را برای کتابخانه‌های C فراهم می‌کند (با پشتیبانی محدود از C++ که نیاز به تنظیم ویژگی cppstd دارد).

کاربرد اولیه rust_bindgen

آنچه در ادامه می‌آید مثالی از نحوه تعریف ماژولی است که از bindgen استفاده می‌کند و نحوه استفاده از آن ماژول به عنوان یک جعبه (crate). اگر نیاز به استفاده از bindgen bindings از طریق یک ماکروی include!() دارید، مانند کد خارجی، به صفحه Source Generators مراجعه کنید.

مثال کتابخانه 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 به اشتراک می‌گذارند. برای مرجع به ویژگی‌های کتابخانه‌ای برجسته Rust مراجعه کنید.

wrapper_src

این مسیر نسبی به یک فایل هدر wrapper است که شامل هدرهای مورد نیاز برای این اتصالات است. پسوند فایل نحوه تفسیر هدر را تعیین می‌کند و مشخص می‌کند که از کدام پرچم -std به طور پیش‌فرض استفاده شود. فرض می‌شود که این یک هدر C است، مگر اینکه پسوند آن .hh یا .hpp باشد. اگر هدر C++ شما باید پسوند دیگری داشته باشد، ویژگی cpp_std را طوری تنظیم کنید که رفتار پیش‌فرض را که فرض می‌کند فایل یک فایل C است، نادیده بگیرد.

منبع_stem

این نام فایل منبع تولید شده است. این فیلد باید تعریف شود، حتی اگر از اتصالات به عنوان جعبه استفاده می‌کنید، زیرا ویژگی stem فقط نام فایل خروجی را برای انواع کتابخانه تولید شده کنترل می‌کند. اگر یک ماژول به چندین مولد منبع (مانند bindgen و protobuf ) به عنوان منبع وابسته است نه به عنوان جعبه از طریق rustlibs ، باید مطمئن شوید که همه مولدهای منبع که وابستگی‌های آن ماژول هستند، مقادیر منحصر به فرد source_stem دارند. ماژول‌های وابسته، منابع را از همه وابستگی‌های SourceProvider که در srcs تعریف شده‌اند، در یک دایرکتوری OUT_DIR مشترک کپی می‌کنند، بنابراین تداخل در source_stem منجر به رونویسی فایل‌های منبع تولید شده در دایرکتوری OUT_DIR می‌شود.

سی_استد

این یک رشته است که نشان می‌دهد از کدام نسخه استاندارد 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 می‌تواند به عنوان یک کتابخانه استفاده شود و یک API ارائه دهد که می‌تواند به عنوان بخشی از یک فایل باینری سفارشی Rust دستکاری شود. فیلد custom_bindgen نام ماژول یک ماژول rust_binary_host را می‌گیرد که از API 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: ["."],
    }