Bazel मॉड्यूल

समस्या की शिकायत करें सोर्स देखें

Bazel मॉड्यूल एक Bazel प्रोजेक्ट है. इसके कई वर्शन हो सकते हैं. इनमें से हर वर्शन, उन दूसरे मॉड्यूल के बारे में मेटाडेटा पब्लिश करता है जिन पर यह निर्भर करता है. यह दूसरे डिपेंडेंसी मैनेजमेंट सिस्टम में, जाने-पहचाने सिद्धांतों के हिसाब से है. जैसे, Maven आर्टफ़ैक्ट, npm पैकेज, Go मॉड्यूल या कार्गो क्रेट.

किसी मॉड्यूल के रिपो रूट में MODULE.bazel फ़ाइल (WORKSPACE फ़ाइल के बगल में) होनी चाहिए. यह फ़ाइल, मॉड्यूल का मेनिफ़ेस्ट है, जो इसके नाम, वर्शन, डायरेक्ट डिपेंडेंसी की सूची, और अन्य जानकारी के बारे में बताती है. एक सामान्य उदाहरण के लिए:

module(name = "my-module", version = "1.0")

bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")

MODULE.bazel फ़ाइलों में उपलब्ध निर्देशों की पूरी सूची देखें.

मॉड्यूल रिज़ॉल्यूशन पूरा करने के लिए, Bazel पहले रूट मॉड्यूल की MODULE.bazel फ़ाइल पढ़ता है. इसके बाद, वह बार-बार Bazel रजिस्ट्री से किसी भी डिपेंडेंसी की MODULE.bazel फ़ाइल को अनुरोध करता है. ऐसा तब तक होता है, जब तक वह पूरे डिपेंडेंसी ग्राफ़ को नहीं खोज लेता.

डिफ़ॉल्ट रूप से, Bazel इस्तेमाल करने के लिए हर मॉड्यूल का एक वर्शन चुनता है. Bazel, हर मॉड्यूल को रेपो की मदद से दिखाता है. साथ ही, हर डेटा को स्टोर करने की जगह तय करने का तरीका जानने के लिए, रजिस्ट्री को फिर से देखता है.

वर्शन फ़ॉर्मैट

Bazel के पास कई तरह का नेटवर्क है. साथ ही, उसके प्रोजेक्ट में अलग-अलग वर्शनिंग स्कीम इस्तेमाल की जाती है. SemVer, अब तक का सबसे लोकप्रिय प्रोजेक्ट है. हालांकि, कुछ ऐसे प्रोजेक्ट भी हैं जिनमें कई अलग-अलग स्कीम का इस्तेमाल किया गया है. जैसे, Abseil, जिनके वर्शन तारीख के हिसाब से होते हैं, जैसे कि 20210324.2).

इस वजह से, Bzlmod ने SumVer की खास जानकारी के ज़्यादा आरामदेह वर्शन को अपनाया. इन अंतरों में ये शामिल हैं:

  • SumVer का कहना है कि वर्शन के "रिलीज़" वाले हिस्से में तीन सेगमेंट होने चाहिए: MAJOR.MINOR.PATCH. Bazel में, इस शर्त को कम किया गया है, ताकि किसी भी संख्या में सेगमेंट बनाए जा सकें.
  • SumVer में, "रिलीज़" वाले हिस्से में हर सेगमेंट में सिर्फ़ अंक होने चाहिए. Bazel में, अक्षरों को भी अनुमति देने के लिए इसे ढीला कर दिया गया है और तुलना सेमैंटिक "प्री-रिलीज़" भाग में "आइडेंटिफ़ायर" से मेल खाते हैं.
  • इसके अलावा, मेजर, माइनर, और पैच वर्शन की बढ़ोतरी के सिमैंटिक लागू नहीं किए जाते. हालांकि, पुराने सिस्टम के साथ काम करने की सुविधा के बारे में जानने के लिए, कम्पैटबिलटी लेवल देखें.

कोई भी मान्य SumVer वर्शन, Bazel मॉड्यूल का मान्य वर्शन होता है. इसके अलावा, SemVer के दो वर्शन a और b, a < b की तुलना सिर्फ़ तब करते हैं, जब बेज़ल मॉड्यूल के वर्शन से इनकी तुलना एक जैसी हो.

वर्शन चुनना

डायमंड डिपेंडेंसी की समस्या के बारे में सोचें. यह वर्शन वाले डिपेंडेंसी मैनेजमेंट स्पेस में ज़रूरी है. मान लें कि आपके पास डिपेंडेंसी ग्राफ़ है:

       A 1.0
      /     \
   B 1.0    C 1.1
     |        |
   D 1.0    D 1.1

D के किस वर्शन का इस्तेमाल करना चाहिए? इस सवाल को हल करने के लिए, Bzlmod, Go मॉड्यूल सिस्टम में पेश किए गए कम से कम वर्शन चुनने (एमवीएस) एल्गोरिदम का इस्तेमाल करता है. MVS यह मानता है कि किसी मॉड्यूल के सभी नए वर्शन, पुराने सिस्टम के साथ काम करते हैं. इसलिए, यह किसी भी डिपेंडेंट के बताए गए सबसे नए वर्शन को चुनता है (हमारे उदाहरण में D 1.1). इसे "मिनिमल" कहा जाता है, क्योंकि D 1.1 सबसे पहला वर्शन है जो हमारी ज़रूरी शर्तों को पूरा कर सकता है — भले ही D 1.2 या इसके बाद के वर्शन मौजूद हों, हम उन्हें नहीं चुनते. MVS का इस्तेमाल करने से, वर्शन चुनने की प्रोसेस बनाई जाती है, जो बहुत अच्छी होती है और फिर से जनरेट की जा सकती है.

यंकेड वर्शन

अगर कुछ वर्शन से बचना चाहिए, तो रजिस्ट्री उन्हें यंकेड के तौर पर एलान कर सकती है. किसी मॉड्यूल के यंक किए गए वर्शन को चुनने पर Bazel एक गड़बड़ी दिखाता है. इस गड़बड़ी को ठीक करने के लिए, किसी नए या नॉन-यंकेड वर्शन पर अपग्रेड करें या 'यंक किए गए वर्शन' को साफ़ तौर पर अनुमति देने के लिए, --allow_yanked_versions फ़्लैग का इस्तेमाल करें.

कम्पैटबिलटी लेवल

Go में, पुराने सिस्टम के साथ काम करने की सुविधा के बारे में एमवीएस का अनुमान काम करता है, क्योंकि यह किसी मॉड्यूल के पिछले वर्शन के साथ काम न करने वाले वर्शन को एक अलग मॉड्यूल की तरह मानता है. इसका मतलब है कि SemVer में A 1.x और A 2.x को अलग-अलग मॉड्यूल माना जाता है. साथ ही, ये रिज़ॉल्व किए गए डिपेंडेंसी ग्राफ़ में एक साथ मौजूद हो सकते हैं. साथ ही, Go के पैकेज पाथ में मेजर वर्शन को कोड में बदलकर ऐसा किया जा सकता है, ताकि कंपाइल करने के समय या लिंक करने के समय को लेकर कोई विवाद न हो.

हालांकि, Bazel इस तरह की गारंटी नहीं दे सकता, इसलिए इसे "मुख्य वर्शन" की संख्या की ज़रूरत होती है, ताकि पुराने सिस्टम के साथ काम न करने वाले वर्शन का पता लगाया जा सके. इस संख्या को कम्पैटबिलटी लेवल कहा जाता है. इसे हर मॉड्यूल वर्शन से अपने module() डायरेक्टिव में बताया जाता है. इस जानकारी के साथ, जब Bazel को पता चलता है कि एक जैसे मॉड्यूल के अलग-अलग लेवल वाले वर्शन, समाधान किए गए डिपेंडेंसी ग्राफ़ में मौजूद हैं, तो उसे गड़बड़ी का मैसेज दिख सकता है.

बदलाव

Bazel मॉड्यूल का रिज़ॉल्यूशन बदलने के लिए, MODULE.bazel फ़ाइल में बदलाव तय करें. सिर्फ़ रूट मॉड्यूल के बदलाव लागू होते हैं — अगर किसी मॉड्यूल का इस्तेमाल डिपेंडेंसी के तौर पर किया जाता है, तो उसके बदलावों को अनदेखा कर दिया जाता है.

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

एकल-वर्शन ओवरराइड

single_version_override का इस्तेमाल कई कामों के लिए किया जा सकता है:

  • version एट्रिब्यूट की मदद से, किसी खास वर्शन पर डिपेंडेंसी पिन की जा सकती है. भले ही, डिपेंडेंसी ग्राफ़ में डिपेंडेंसी के किसी वर्शन का अनुरोध किया गया हो.
  • registry एट्रिब्यूट की मदद से, यह डिपेंडेंसी किसी खास रजिस्ट्री से आने के लिए सेट की जा सकती है. इससे रजिस्ट्री चुनने की सामान्य प्रोसेस पूरी नहीं की जा सकती.
  • patch* एट्रिब्यूट की मदद से, डाउनलोड किए गए मॉड्यूल पर लागू करने के लिए, पैच का सेट तय किया जा सकता है.

ये सभी एट्रिब्यूट ज़रूरी नहीं हैं. साथ ही, इन्हें एक-दूसरे के साथ मिलाया जा सकता है.

एक से ज़्यादा वर्शन में बदलाव करना

multiple_version_override को डिपेंडेंसी के ग्राफ़ में, एक ही मॉड्यूल के कई वर्शन को एक साथ इस्तेमाल करने की अनुमति देने के लिए तय किया जा सकता है.

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

उदाहरण के लिए, अगर वर्शन 1.1, 1.3, 1.5, 1.7, और 2.0, डिपेंडेंसी ग्राफ़ में रिज़ॉल्यूशन से पहले मौजूद हैं और मेजर वर्शन, कम्पैटबिलटी लेवल है:

  • एक से ज़्यादा वर्शन में होने वाले बदलाव से 1.3, 1.7, और 2.0 में 1.1 को 1.3 में अपग्रेड किया जा रहा है, 1.5 को 1.7 में अपग्रेड किया जा रहा है, और पहले वाले वर्शन में कोई बदलाव नहीं किया गया है.
  • एक से ज़्यादा वर्शन में बदलाव करने से, 1.5 और 2.0 को सेट करने में गड़बड़ी हो सकती है. ऐसा इसलिए, क्योंकि 1.7 के पास अपग्रेड करने के लिए, काम करने के उसी लेवल का कोई नया वर्शन नहीं है जिस पर अपग्रेड किया जा सकता है.
  • एक से ज़्यादा वर्शन में बदलाव करने से, 1.9 और 2.0 को अनुमति देने पर गड़बड़ी हो सकती है, क्योंकि 1.9, रिज़ॉल्यूशन से पहले डिपेंडेंसी ग्राफ़ में मौजूद नहीं है.

इसके अलावा, उपयोगकर्ता registry एट्रिब्यूट का इस्तेमाल करके, रजिस्ट्री को भी बदल सकते हैं. यह उसी तरह होता है जिस तरह एक वर्शन में होने वाले बदलाव के लिए किया जाता है.

नॉन-रजिस्ट्री ओवरराइड

नॉन-रजिस्ट्री ओवरराइड करने से वर्शन रिज़ॉल्यूशन से एक मॉड्यूल पूरी तरह से हटा दिया जाता है. Bazel इन MODULE.bazel फ़ाइलों को किसी रजिस्ट्री से नहीं, बल्कि रेपो से अनुरोध करता है.

Bazel के साथ इन नॉन-रजिस्ट्री ओवरराइड का इस्तेमाल किया जा सकता है:

रिपॉज़िटरी के नाम और स्ट्रिक्ट डिप

मॉड्यूल का बैक करने वाले रेपो का कैननिकल नाम module_name~version है (उदाहरण के लिए, bazel_skylib~1.0.3). ऐसे मॉड्यूल जो नॉन-रजिस्ट्री ओवरराइड वाले हैं, उनके लिए version वाले हिस्से की जगह स्ट्रिंग override का इस्तेमाल करें. ध्यान दें कि कैननिकल नाम का फ़ॉर्मैट कोई एपीआई नहीं है. आपको इस फ़ॉर्मैट पर निर्भर रहना चाहिए और इसे कभी भी बदला जा सकता है.

मॉड्यूल का साफ़ तौर पर दिखने वाला नाम, जो मॉड्यूल को उसके डायरेक्ट डिपेंडेंट से डिफ़ॉल्ट रूप से बैक करता है, डिफ़ॉल्ट रूप से उसके मॉड्यूल का नाम होता है. ऐसा तब तक होता है, जब तक bazel_dep डायरेक्टिव के repo_name एट्रिब्यूट से कुछ और न कहा गया हो. ध्यान दें कि इसका मतलब है कि मॉड्यूल सिर्फ़ सीधे तौर पर अपनी डिपेंडेंसी ढूंढ सकता है. यह ट्रांज़िशन डिपेंडेंसी में बदलाव की वजह से, गलती से होने वाली समस्याओं को रोकने में मदद करता है.

मॉड्यूल एक्सटेंशन की मदद से, मॉड्यूल के दिखने वाले स्कोप में अतिरिक्त डेटा स्टोर भी किया जा सकता है.