सोर्स जनरेटर

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

सभी सोर्स जनरेटर, बिल्ड-सिस्टम की एक जैसी सुविधाएं देते हैं. सोर्स जनरेट करने के लिए, बिल्ड सिस्टम के साथ काम करने वाले तीन उदाहरण यहां दिए गए हैं: bindgen का इस्तेमाल करके सी बाइंडिंग जनरेट करना, एआईडीएल इंटरफ़ेस, और प्रोटोबफ़ इंटरफ़ेस.

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

सोर्स कोड जनरेट करने वाले हर Rust मॉड्यूल को एक क्रेट के तौर पर इस्तेमाल किया जा सकता है. इसे ठीक उसी तरह इस्तेमाल किया जा सकता है जैसे rust_library के तौर पर तय किया गया हो. (इसका मतलब है कि इसे rustlibs, rlibs, और dylibs प्रॉपर्टी में डिपेंडेंसी के तौर पर तय किया जा सकता है.) प्लैटफ़ॉर्म कोड के लिए, इस्तेमाल करने का सबसे अच्छा तरीका यह है कि जनरेट किए गए सोर्स को क्रेट के तौर पर इस्तेमाल किया जाए. हालांकि, जनरेट किए गए सोर्स के लिए include! मैक्रो काम करता है, लेकिन इसका मुख्य मकसद external/ में मौजूद तीसरे पक्ष के कोड को सपोर्ट करना है.

कुछ मामलों में, प्लैटफ़ॉर्म कोड अब भी include!() मैक्रो के ज़रिए जनरेट किए गए सोर्स का इस्तेमाल कर सकता है. जैसे, जब किसी genrule मॉड्यूल का इस्तेमाल करके, यूनीक तरीके से सोर्स जनरेट किया जाता है.

जनरेट किए गए सोर्स को शामिल करने के लिए, include!() का इस्तेमाल करें

जनरेट किए गए सोर्स को क्रेट के तौर पर इस्तेमाल करने के बारे में, हर मॉड्यूल पेज पर दिए गए उदाहरणों में बताया गया है. इस सेक्शन में, include!() मैक्रो की मदद से जनरेट किए गए सोर्स को रेफ़रंस करने का तरीका बताया गया है. ध्यान दें कि यह प्रोसेस, सभी सोर्स जनरेटर के लिए एक जैसी होती है.

पूर्वापेक्षा

यह उदाहरण इस आधार पर दिया गया है कि आपने rust_bindgen मॉड्यूल (libbuzz_bindgen) तय किया है और include!() मैक्रो का इस्तेमाल करने के लिए, जनरेट किए गए सोर्स को शामिल करने के चरणों पर जा सकते हैं. अगर आपने ऐसा नहीं किया है, तो कृपया रस्ट बाइंडजेन मॉड्यूल तय करना पर जाएं, 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 नहीं है जहां डिपेंडेंसी, जनरेट किए गए सोर्स को आउटपुट करती हों.

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

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

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


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

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