উৎস জেনারেটর

এই পৃষ্ঠাটিতে জেনারেটেড সোর্স কীভাবে সমর্থিত হয় এবং বিল্ড সিস্টেমে এটি কীভাবে ব্যবহার করা যেতে পারে, তার একটি সামগ্রিক ধারণা দেওয়া হয়েছে।

সমস্ত সোর্স জেনারেটর একই ধরনের বিল্ড-সিস্টেম কার্যকারিতা প্রদান করে। বিল্ড-সিস্টেম সমর্থিত সোর্স জেনারেশনের তিনটি ব্যবহার হলো বাইন্ডজেন, এআইডিএল ইন্টারফেস এবং প্রোটোবাফ ইন্টারফেস ব্যবহার করে সি বাইন্ডিং তৈরি করা।

তৈরি উৎস থেকে ক্রেট

প্রতিটি রাস্ট মডিউল যা সোর্স কোড তৈরি করে, তাকে একটি ক্রেট হিসেবে ব্যবহার করা যেতে পারে, ঠিক যেমনটি একটি 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 শুধুমাত্র একটি সোর্স ফাইল গ্রহণ করে যা কোনো বাইনারি বা লাইব্রেরির এন্ট্রি পয়েন্টকে প্রতিনিধিত্ব করে। এটি আশা করে যে সোর্স ট্রি এমনভাবে গঠিত হবে যাতে সমস্ত প্রয়োজনীয় সোর্স ফাইল স্বয়ংক্রিয়ভাবে খুঁজে পাওয়া যায়। এর মানে হলো, জেনারেটেড সোর্স অবশ্যই সোর্স ট্রিতে রাখতে হবে, অথবা সোর্সের মধ্যে একটি include ডিরেক্টিভের মাধ্যমে সরবরাহ করতে হবে।

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

এই পার্থক্যটির সাথে মানিয়ে চলার জন্য রাস্ট কমিউনিটি build.rs স্ক্রিপ্ট এবং Cargo বিল্ড এনভায়রনমেন্ট সম্পর্কিত কিছু অনুমানের উপর নির্ভর করে। বিল্ড করার সময়, cargo কমান্ডটি একটি OUT_DIR এনভায়রনমেন্ট ভ্যারিয়েবল সেট করে, যেখানে build.rs স্ক্রিপ্টগুলো জেনারেট করা সোর্স কোড রাখবে বলে আশা করা হয়। সোর্স কোড অন্তর্ভুক্ত করতে নিম্নলিখিত কমান্ডটি ব্যবহার করুন:

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

এটি সুং-এর জন্য একটি চ্যালেঞ্জ তৈরি করে, কারণ প্রতিটি মডিউলের আউটপুট তাদের নিজস্ব out/ ডিরেক্টরিতে রাখা হয় 1। এমন কোনো একক OUT_DIR নেই যেখানে ডিপেন্ডেন্সিগুলো তাদের তৈরি করা সোর্স আউটপুট করে।

প্ল্যাটফর্ম কোডের জন্য, AOSP বিভিন্ন কারণে জেনারেটেড সোর্সকে একটি ক্রেটে প্যাকেজ করতে পছন্দ করে যা ইম্পোর্ট করা যায়:

  • তৈরি হওয়া সোর্স ফাইলের নামগুলোর মধ্যে সংঘর্ষ প্রতিরোধ করুন।
  • পুরো ট্রি জুড়ে চেক-ইন করা এমন বয়লারপ্লেট কোড কমিয়ে আনুন যার রক্ষণাবেক্ষণ প্রয়োজন। জেনারেটেড সোর্সকে একটি ক্রেটে কম্পাইল করার জন্য প্রয়োজনীয় যেকোনো বয়লারপ্লেট কোড কেন্দ্রীয়ভাবে রক্ষণাবেক্ষণ করা যেতে পারে।
  • জেনারেট করা কোড এবং তার চারপাশের ক্রেটের মধ্যে পরোক্ষ মিথস্ক্রিয়া এড়িয়ে চলুন।
  • সাধারণভাবে ব্যবহৃত জেনারেটেড সোর্সগুলোকে ডাইনামিকভাবে লিঙ্ক করার মাধ্যমে মেমোরি ও ডিস্কের ওপর চাপ কমান।

এর ফলে, অ্যান্ড্রয়েডের সমস্ত রাস্ট সোর্স জেনারেশন মডিউল টাইপ এমন কোড তৈরি করে যা একটি ক্রেট হিসাবে কম্পাইল এবং ব্যবহার করা যায়। যদি একটি মডিউলের জন্য তৈরি করা সমস্ত সোর্স ডিপেন্ডেন্সি কার্গোর মতো একটি একক পার-মডিউল ডিরেক্টরিতে কপি করা হয়, তবে সোং কোনো পরিবর্তন ছাড়াই থার্ড-পার্টি ক্রেট সমর্থন করে। এই ধরনের ক্ষেত্রে, মডিউলটি কম্পাইল করার সময় সোং OUT_DIR এনভায়রনমেন্ট ভেরিয়েবলটিকে সেই ডিরেক্টরিতে সেট করে, যাতে তৈরি করা সোর্সটি খুঁজে পাওয়া যায়। তবে, পূর্বে বর্ণিত কারণগুলির জন্য, প্ল্যাটফর্ম কোডে এই পদ্ধতিটি শুধুমাত্র একান্ত প্রয়োজনীয় হলেই ব্যবহার করা সর্বোত্তম পন্থা।


  1. এতে C/C++ এবং অনুরূপ ভাষাগুলোর ক্ষেত্রে কোনো সমস্যা হয় না, কারণ তৈরি হওয়া সোর্স কোডের পাথ সরাসরি কম্পাইলারে সরবরাহ করা হয়।

  2. যেহেতু include! টেক্সচুয়াল ইনক্লুশনের মাধ্যমে কাজ করে, তাই এটি এনক্লোজিং নেমস্পেস থেকে ভ্যালু রেফারেন্স করতে পারে, নেমস্পেস পরিবর্তন করতে পারে, অথবা #![foo] এর মতো কনস্ট্রাক্ট ব্যবহার করতে পারে। এই ইমপ্লিসিট ইন্টারঅ্যাকশনগুলো রক্ষণাবেক্ষণ করা কঠিন হতে পারে। যখন ক্রেটের বাকি অংশের সাথে ইন্টারঅ্যাকশন সত্যিই প্রয়োজন, তখন সর্বদা ম্যাক্রো ব্যবহার করুন।