सोर्स जनरेटर

इस पेज पर, जनरेट किए गए सोर्स के काम करने के तरीके और उसे बिल्ड सिस्टम में इस्तेमाल करने के तरीके के बारे में खास जानकारी दी गई है.

सभी सोर्स जनरेटर, बिल्ड-सिस्टम से मिलती-जुलती सुविधाएं देते हैं. सोर्स जनरेशन के इस्तेमाल के तीन उदाहरणों में, बाइन्ड करने वाले टूल, AIDL इंटरफ़ेस, और प्रोटोबस इंटरफ़ेस का इस्तेमाल करके C बाइंडिंग जनरेट की जा रही हैं.

जनरेट किए गए सोर्स से क्रेट

सोर्स कोड जनरेट करने वाले हर Rust मॉड्यूल का इस्तेमाल, क्रेट के तौर पर किया जा सकता है. ठीक वैसे ही जैसे कि उसे 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!("/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 नहीं होता जहां डिपेंडेंसी अपने जनरेट किए गए सोर्स का आउटपुट देती हैं.

प्लैटफ़ॉर्म कोड के लिए, एओएसपी, पैकेजिंग के ज़रिए जनरेट किए गए सोर्स को ऐसे क्रेट में प्राथमिकता देता है जिसे इंपोर्ट किया जा सकता है. इसकी कई वजहें हैं:

  • जनरेट की गई सोर्स फ़ाइल के नामों को एक जैसा होने से रोकना.
  • पूरे ट्री में, छोटे-मोटे बदलाव वाले कोड को कम करें. जनरेट किए गए सोर्स को कंपाइल करके क्रेट में बदलने के लिए, ज़रूरी किसी भी बॉयलरप्लेट को एक ही जगह से मैनेज किया जा सकता है.
  • जनरेट किए गए कोड और आस-पास के क्रेट के बीच,2 इंप्लिसिट इंटरैक्शन से बचें.
  • आम तौर पर इस्तेमाल किए जाने वाले सोर्स को डाइनैमिक तरीके से लिंक करके, मेमोरी और डिस्क पर दबाव कम करें.

इस वजह से, Android के Rust सोर्स जनरेशन मॉड्यूल टाइप, ऐसा कोड जनरेट करते हैं जिसे क्रेट के तौर पर कंपाइल और इस्तेमाल किया जा सकता है. अगर किसी मॉड्यूल के लिए जनरेट की गई सभी सोर्स डिपेंडेंसी को कार्गो की तरह ही एक हर मॉड्यूल डायरेक्ट्री में कॉपी कर लिया जाता है, तो सूंग अब भी बिना किसी बदलाव के तीसरे पक्ष के क्रेटों के साथ काम करता है. ऐसे मामलों में, सूंग मॉड्यूल को कंपाइल करते समय OUT_DIR एनवायरमेंट वैरिएबल को उस डायरेक्ट्री में सेट करता है, ताकि जनरेट किया गया सोर्स ढूंढा जा सके. हालांकि, पहले बताई गई वजहों से, प्लैटफ़ॉर्म कोड में इस तरीके का इस्तेमाल सिर्फ़ तब करना चाहिए, जब ज़रूरी हो.


  1. इससे C/C++ और इससे मिलती-जुलती भाषाओं के लिए कोई समस्या नहीं आती, क्योंकि जनरेट किए गए सोर्स का पाथ सीधे कंपाइलर को दिया जाता है. 

  2. include!, टेक्स्ट को शामिल करके काम करता है. इसलिए, यह नेमस्पेस में मौजूद वैल्यू का रेफ़रंस दे सकता है, नेमस्पेस में बदलाव कर सकता है या #![foo] जैसे कंस्ट्रक्ट का इस्तेमाल कर सकता है. इन छिपे हुए इंटरैक्शन को बनाए रखना मुश्किल हो सकता है. जब क्रेट के बाकी हिस्सों के साथ इंटरैक्ट करना ज़रूरी हो, तो हमेशा मैक्रो का इस्तेमाल करें.