ژنراتورهای منبع

این صفحه نمای سطح بالایی از نحوه پشتیبانی از منبع تولید شده و نحوه استفاده از آن در سیستم ساخت ارائه می‌دهد.

همه مولدهای منبع، عملکرد سیستم ساخت مشابهی را ارائه می‌دهند. سه مورد استفاده از مولد منبع که توسط سیستم ساخت پشتیبانی می‌شوند، تولید اتصالات C با استفاده از رابط‌های bindgen، AIDL و protobuf هستند.

جعبه‌ها از منبع تولید شده

هر ماژول Rust که کد منبع تولید می‌کند، می‌تواند به عنوان یک جعبه (crate) استفاده شود، دقیقاً مانند زمانی که به عنوان یک rust_library تعریف شده باشد. (این بدان معناست که می‌تواند به عنوان یک وابستگی در ویژگی‌های rustlibs ، rlibs و dylibs تعریف شود.) بهترین الگوی استفاده برای کد پلتفرم، استفاده از منبع تولید شده به عنوان یک جعبه است. اگرچه ماکروی include! برای منبع تولید شده پشتیبانی می‌شود، هدف اصلی آن پشتیبانی از کد شخص ثالثی است که در external/ قرار دارد.

مواردی وجود دارد که کد پلتفرم ممکن است همچنان از منبع تولید شده از طریق ماکروی include!() استفاده کند، مانند زمانی که از یک ماژول genrule برای تولید منبع به روشی منحصر به فرد استفاده می‌کنید.

برای اضافه کردن سورس تولید شده از include!() استفاده کنید.

استفاده از منبع تولید شده به عنوان یک جعبه، در مثال‌های موجود در هر صفحه ماژول (مربوط به آن) پوشش داده شده است. این بخش نحوه ارجاع به منبع تولید شده از طریق ماکروی include!() را نشان می‌دهد. توجه داشته باشید که این فرآیند برای همه مولدهای منبع مشابه است.

پیش‌نیاز

این مثال بر این فرض استوار است که شما یک ماژول rust_bindgen ( libbuzz_bindgen ) تعریف کرده‌اید و می‌توانید به مراحل مربوط به اضافه کردن منبع تولید شده برای استفاده از include!() بروید. اگر این کار را نکرده‌اید، لطفاً به تعریف ماژول rust bindgen بروید، libbuzz_bindgen را ایجاد کنید، سپس به اینجا برگردید.

توجه داشته باشید که بخش‌های فایل ساخت این برای همه مولدهای منبع قابل استفاده است.

مراحل اضافه کردن منبع تولید شده

external/rust/hello_bindgen/Android.bp را با محتوای زیر ایجاد کنید:

rust_binary {
   name: "hello_bzip_bindgen_include",
   srcs: [
         // The primary rust source file must come first in this list.
         "src/lib.rs",

         // The module providing the bindgen bindings is
         // included in srcs prepended by ":".
         ":libbuzz_bindgen",
    ],

    // Dependencies need to be redeclared when generated source is used via srcs.
    shared_libs: [
        "libbuzz",
    ],
}

external/rust/hello_bindgen/src/bindings.rs را با محتوای زیر ایجاد کنید:

#![allow(clippy::all)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
#![allow(missing_docs)]

// Note that "bzip_bindings.rs" here must match the source_stem property from
// the rust_bindgen module.
include!(concat!(env!("OUT_DIR"), "/bzip_bindings.rs"));

external/rust/hello_bindgen/src/lib.rs را با محتوای زیر ایجاد کنید:

mod bindings;

fn main() {
    let mut x = bindings::foo { x: 2 };
    unsafe { bindings::fizz(1, &mut x as *mut bindings::foo) }
}

چرا جعبه‌ها برای منبع تولید شده

برخلاف کامپایلرهای C/C++، rustc فقط یک فایل منبع واحد را می‌پذیرد که نشان‌دهنده‌ی نقطه‌ی ورود به یک فایل باینری یا کتابخانه است. Rustc انتظار دارد که درخت منبع به گونه‌ای ساختار یافته باشد که تمام فایل‌های منبع مورد نیاز بتوانند به طور خودکار کشف شوند. این بدان معناست که منبع تولید شده یا باید در درخت منبع قرار گیرد، یا از طریق یک دستورالعمل include در منبع ارائه شود:

include!("/path/to/hello.rs");

جامعه Rust برای کار با این تفاوت به اسکریپت‌های build.rs و فرضیات مربوط به محیط ساخت Cargo وابسته است. هنگام ساخت، دستور cargo یک متغیر محیطی OUT_DIR تنظیم می‌کند که انتظار می‌رود اسکریپت‌های build.rs کد منبع تولید شده را در آن قرار دهند. از دستور زیر برای افزودن کد منبع استفاده کنید:

include!(concat!(env!("OUT_DIR"), "/hello.rs"));

این موضوع برای Soong چالشی ایجاد می‌کند، زیرا خروجی‌های هر ماژول در دایرکتوری out/ 1 مخصوص به خود قرار می‌گیرند. هیچ OUT_DIR واحدی وجود ندارد که وابستگی‌ها منبع تولید شده خود را در آن خروجی دهند.

برای کد پلتفرم، AOSP به چند دلیل ترجیح می‌دهد منبع تولید شده را در جعبه‌ای که بتوان آن را وارد کرد، بسته‌بندی کند:

  • از تداخل نام فایل‌های منبع تولید شده جلوگیری کنید.
  • کاهش کدهای تکراری که در سراسر درخت کد بررسی می‌شوند و نیاز به نگهداری دارند. هر کد تکراری که برای کامپایل منبع تولید شده در یک جعبه لازم است، می‌تواند به صورت مرکزی نگهداری شود.
  • از تعاملات ضمنی بین کد تولید شده و جعبه اطراف آن اجتناب کنید.
  • با پیوند پویای منابع تولید شده‌ی پرکاربرد، فشار روی حافظه و دیسک را کاهش دهید.

در نتیجه، تمام انواع ماژول‌های تولید سورس Rust اندروید، کدی تولید می‌کنند که می‌تواند کامپایل شده و به عنوان یک جعبه (crate) استفاده شود. Soong همچنان از جعبه‌های شخص ثالث بدون تغییر پشتیبانی می‌کند، اگر تمام وابستگی‌های سورس تولید شده برای یک ماژول در یک دایرکتوری واحد برای هر ماژول، مشابه Cargo، کپی شوند. در چنین مواردی، Soong هنگام کامپایل ماژول، متغیر محیطی OUT_DIR را روی آن دایرکتوری تنظیم می‌کند، بنابراین می‌توان سورس تولید شده را پیدا کرد. با این حال، به دلایلی که قبلاً توضیح داده شد، بهتر است فقط در مواقع ضروری از این مکانیزم در کد پلتفرم استفاده شود.


  1. این موضوع هیچ مشکلی برای زبان‌های C/C++ و زبان‌های مشابه ایجاد نمی‌کند، زیرا مسیر منبع تولید شده مستقیماً در اختیار کامپایلر قرار می‌گیرد.

  2. از آنجایی که include! با گنجاندن متنی کار می‌کند، ممکن است به مقادیری از فضای نامِ دربرگیرنده ارجاع دهد، فضای نام را تغییر دهد یا از ساختارهایی مانند #![foo] استفاده کند. حفظ این تعاملات ضمنی می‌تواند دشوار باشد. همیشه ماکروها را ترجیح دهید وقتی که تعامل با بقیه‌ی جعبه واقعاً مورد نیاز است.