Bazel मॉड्यूल, Bazel प्रोजेक्ट होता है. इसके कई वर्शन हो सकते हैं. हर वर्शन, उन अन्य मॉड्यूल के बारे में मेटाडेटा पब्लिश करता है जिन पर वह निर्भर करता है. यह अन्य डिपेंडेंसी मैनेजमेंट सिस्टम में मौजूद जाने-पहचाने कॉन्सेप्ट के जैसा ही है. जैसे, Maven आर्टफ़ैक्ट, npm पैकेज, Go मॉड्यूल या Cargo क्रेट.
किसी मॉड्यूल के लिए, उसके रेपो रूट में MODULE.bazel फ़ाइल होना ज़रूरी है. यह फ़ाइल, मॉड्यूल का मेनिफ़ेस्ट है. इसमें मॉड्यूल का नाम, वर्शन, सीधे तौर पर निर्भरता रखने वाले मॉड्यूल की सूची, और अन्य जानकारी दी गई है. सामान्य उदाहरण के लिए:
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 फ़ाइल को पढ़ता है. इसके बाद, यह किसी भी डिपेंडेंसी की MODULE.bazel फ़ाइल के लिए, Bazel रजिस्ट्री से बार-बार अनुरोध करता है. ऐसा तब तक किया जाता है, जब तक कि उसे पूरा डिपेंडेंसी ग्राफ़ नहीं मिल जाता.
इसके बाद, Bazel डिफ़ॉल्ट रूप से इस्तेमाल करने के लिए, हर मॉड्यूल का एक वर्शन चुनता है. Bazel, हर मॉड्यूल को एक रेपो के तौर पर दिखाता है. साथ ही, हर रेपो को तय करने का तरीका जानने के लिए, रजिस्ट्री से फिर से सलाह लेता है.
वर्शन का फ़ॉर्मैट
Bazel का एक बड़ा ईकोसिस्टम है और प्रोजेक्ट में वर्शनिंग की अलग-अलग स्कीम का इस्तेमाल किया जाता है. सबसे ज़्यादा इस्तेमाल किया जाने वाला वर्शनिंग सिस्टम SemVer है. हालांकि, Abseil जैसे कई प्रोजेक्ट में अलग-अलग वर्शनिंग सिस्टम का इस्तेमाल किया जाता है. Abseil के वर्शन, तारीख के हिसाब से तय किए जाते हैं. उदाहरण के लिए, 20210324.2).
इस वजह से, Bazel, SemVer स्पेसिफ़िकेशन के ज़्यादा आसान वर्शन का इस्तेमाल करता है. इन दोनों में ये अंतर हैं:
- SemVer के मुताबिक, वर्शन के "रिलीज़" वाले हिस्से में तीन सेगमेंट होने चाहिए:
MAJOR.MINOR.PATCH. Bazel में, इस शर्त को आसान बना दिया गया है, ताकि किसी भी संख्या में सेगमेंट बनाए जा सकें. - SemVer में, "रिलीज़" वाले हिस्से के हर सेगमेंट में सिर्फ़ अंक होने चाहिए. Bazel में, अक्षरों को भी अनुमति देने के लिए इसे कम कर दिया गया है. साथ ही, तुलना के सिमैंटिक, "prerelease" वाले हिस्से में मौजूद "पहचानकर्ताओं" से मेल खाते हैं.
- इसके अलावा, मेजर, माइनर, और पैच वर्शन के सिमैंटिक को लागू नहीं किया जाता.
कोई भी मान्य SemVer वर्शन, Bazel मॉड्यूल का मान्य वर्शन होता है. इसके अलावा, दो SemVer वर्शन a और b की तुलना a < b से तब ही की जाती है, जब Bazel मॉड्यूल वर्शन के तौर पर तुलना करने पर भी ऐसा ही होता है.
आखिर में, मॉड्यूल के वर्शन के बारे में ज़्यादा जानने के लिए, MODULE.bazel
अक्सर पूछे जाने वाले सवाल देखें.
वर्शन चुनना
डायमंड डिपेंडेंसी की समस्या पर विचार करें. यह वर्शन वाली डिपेंडेंसी मैनेजमेंट स्पेस में एक आम समस्या है. मान लें कि आपके पास यह डिपेंडेंसी ग्राफ़ है:
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
D के किस वर्शन का इस्तेमाल किया जाना चाहिए? इस सवाल का जवाब देने के लिए, Bazel, Go मॉड्यूल सिस्टम में पेश किए गए मिनिमल वर्शन सिलेक्शन (एमवीएस) एल्गोरिदम का इस्तेमाल करता है. MVS यह मानकर चलता है कि मॉड्यूल के सभी नए वर्शन, पिछले वर्शन के साथ काम करते हैं. इसलिए, यह किसी भी डिपेंडेंट (हमारे उदाहरण में D 1.1) के ज़रिए तय किए गए सबसे नए वर्शन को चुनता है. इसे "कम से कम" कहा जाता है, क्योंकि D 1.1 ऐसा पहला वर्शन है जो हमारी ज़रूरी शर्तों को पूरा कर सकता है. भले ही, D 1.2 या नया वर्शन मौजूद हो, हम उन्हें नहीं चुनते. एमवीएस का इस्तेमाल करने से, वर्शन चुनने की ऐसी प्रोसेस बनती है जो हाई-फ़िडेलिटी और दोहराई जा सकने वाली होती है.
Yank किए गए वर्शन
अगर किसी वर्शन का इस्तेमाल नहीं करना चाहिए, तो रजिस्ट्री उसे yanked के तौर पर मार्क कर सकती है. जैसे, सुरक्षा से जुड़े जोखिम की वजह से. किसी मॉड्यूल के यैंक किए गए वर्शन को चुनने पर, Bazel एक गड़बड़ी दिखाता है. इस गड़बड़ी को ठीक करने के लिए, या तो नए और बिना हटाए गए वर्शन पर अपग्रेड करें या हटाए गए वर्शन को साफ़ तौर पर अनुमति देने के लिए, --allow_yanked_versions फ़्लैग का इस्तेमाल करें.
बदली गई कीमत
Bazel मॉड्यूल रिज़ॉल्यूशन के व्यवहार में बदलाव करने के लिए, MODULE.bazel फ़ाइल में ओवरराइड तय करें. सिर्फ़ रूट मॉड्यूल के ओवरराइड लागू होते हैं. अगर किसी मॉड्यूल का इस्तेमाल डिपेंडेंसी के तौर पर किया जाता है, तो उसके ओवरराइड को अनदेखा कर दिया जाता है.
हर ओवरराइड को किसी मॉड्यूल के नाम के लिए तय किया जाता है. इससे डिपेंडेंसी ग्राफ़ में मौजूद उसके सभी वर्शन पर असर पड़ता है. हालांकि, सिर्फ़ रूट मॉड्यूल के ओवरराइड लागू होते हैं, लेकिन ये ऐसे ट्रांज़िटिव डिपेंडेंसी के लिए हो सकते हैं जिन पर रूट मॉड्यूल सीधे तौर पर निर्भर नहीं होता.
एक वर्शन को ओवरराइड करना
single_version_override कई कामों के लिए इस्तेमाल किया जाता है:
versionएट्रिब्यूट की मदद से, किसी डिपेंडेंसी को किसी खास वर्शन पर पिन किया जा सकता है. भले ही, डिपेंडेंसी ग्राफ़ में डिपेंडेंसी के किसी भी वर्शन का अनुरोध किया गया हो.registryएट्रिब्यूट की मदद से, इस डिपेंडेंसी को सामान्य रजिस्ट्री चुनने की प्रोसेस के बजाय, किसी खास रजिस्ट्री से लाने के लिए मजबूर किया जा सकता है.patch*एट्रिब्यूट की मदद से, डाउनलोड किए गए मॉड्यूल पर लागू करने के लिए पैच का सेट तय किया जा सकता है.
ये सभी एट्रिब्यूट ज़रूरी नहीं हैं. इन्हें एक-दूसरे के साथ मिलाकर इस्तेमाल किया जा सकता है.
कई वर्शन को ओवरराइड करना
multiple_version_override को यह तय करने के लिए सेट किया जा सकता है कि एक ही मॉड्यूल के कई वर्शन, हल किए गए डिपेंडेंसी ग्राफ़ में एक साथ मौजूद रहें.
अगर डिपेंडेंसी ग्राफ़ में एक ही मॉड्यूल के कई वर्शन मौजूद हैं, तो 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.9और2.0को बदलने पर गड़बड़ी होती है, क्योंकि समाधान से पहले1.9, डिपेंडेंसी ग्राफ़ में मौजूद नहीं होता.
इसके अलावा, उपयोगकर्ता registry एट्रिब्यूट का इस्तेमाल करके भी रजिस्ट्री को बदल सकते हैं. यह सिंगल-वर्शन ओवरराइड की तरह ही काम करता है.
रजिस्ट्री के बाहर के ओवरराइड
नॉन-रजिस्ट्री ओवरराइड, वर्शन रिज़ॉल्यूशन से किसी मॉड्यूल को पूरी तरह हटा देते हैं. Bazel, इन MODULE.bazel फ़ाइलों का अनुरोध किसी रजिस्ट्री से नहीं करता, बल्कि सीधे तौर पर रिपॉज़िटरी से करता है.
Bazel, रजिस्ट्री से बाहर के इन ओवरराइड के साथ काम करता है:
ध्यान दें कि सोर्स संग्रह MODULE.bazel में वर्शन की वैल्यू सेट करने से, कुछ समस्याएं हो सकती हैं. ऐसा तब होता है, जब मॉड्यूल को नॉन-रजिस्ट्री ओवरराइड से बदला जा रहा हो. इस बारे में ज़्यादा जानने के लिए, MODULE.bazel अक्सर पूछे जाने वाले सवाल देखें.
उन रिपॉज़िटरी को तय करें जो Bazel मॉड्यूल को नहीं दिखाती हैं
bazel_dep की मदद से, ऐसे रेपो तय किए जा सकते हैं जो अन्य Bazel मॉड्यूल को दिखाते हैं.
कभी-कभी, ऐसी रिपो को तय करने की ज़रूरत होती है जो Bazel मॉड्यूल को नहीं दिखाती है. उदाहरण के लिए, ऐसी रिपो जिसमें डेटा के तौर पर पढ़ी जाने वाली सामान्य JSON फ़ाइल शामिल होती है.
ऐसे मामले में, use_repo_rule
डायरेक्टिव का इस्तेमाल करके, सीधे तौर पर किसी रेपो को तय किया जा सकता है. इसके लिए, रेपो के नियम को लागू करना होगा. यह रिपो सिर्फ़ उस मॉड्यूल को दिखेगी जिसमें इसे तय किया गया है.
यह सुविधा, मॉड्यूल एक्सटेंशन के लिए इस्तेमाल किए जाने वाले मैकेनिज़्म का इस्तेमाल करती है. इससे आपको ज़्यादा फ़्लेक्सिबिलिटी के साथ रिपॉज़िटरी तय करने की सुविधा मिलती है.
रिपॉज़िटरी के नाम और स्ट्रिक्ट डिपेंडेंसी
किसी मॉड्यूल को सीधे तौर पर इस्तेमाल करने वाले मॉड्यूल के लिए, उसे बैक करने वाले रेपो का दिखने वाला नाम डिफ़ॉल्ट रूप से उसके मॉड्यूल का नाम होता है. हालांकि, अगर bazel_dep डायरेक्टिव के repo_name एट्रिब्यूट में कोई दूसरा नाम दिया गया है, तो वह नाम इस्तेमाल किया जाता है. ध्यान दें कि इसका मतलब है कि कोई मॉड्यूल सिर्फ़ अपनी डायरेक्ट डिपेंडेंसी ढूंढ सकता है. इससे ट्रांज़िटिव डिपेंडेंसी में बदलावों की वजह से होने वाली अनचाही रुकावटों से बचा जा सकता है.
किसी मॉड्यूल को बैक करने वाले रेपो का कैननिकल नाम, module_name+version (उदाहरण के लिए, bazel_skylib+1.0.3) या module_name+ (उदाहरण के लिए, bazel_features+) होता है. यह इस बात पर निर्भर करता है कि पूरे डिपेंडेंसी ग्राफ़ में मॉड्यूल के कई वर्शन हैं या नहीं. इसके बारे में जानने के लिए, multiple_version_override देखें.
ध्यान दें कि कैननिकल नाम का फ़ॉर्मैट ऐसा एपीआई नहीं है जिस पर आपको भरोसा करना चाहिए. साथ ही, इसमें किसी भी समय बदलाव किया जा सकता है. कैननिकल नाम को हार्ड-कोड करने के बजाय,
इसे सीधे Bazel से पाने के लिए, इस्तेमाल किए जा सकने वाले तरीके का इस्तेमाल करें:
- BUILD और
.bzlफ़ाइलों में,Labelइंस्टेंस परLabel.repo_nameका इस्तेमाल करें.यह इंस्टेंस, repo के नाम से दी गई लेबल स्ट्रिंग से बनाया गया है. उदाहरण के लिए,Label("@bazel_skylib").repo_name. - रनफ़ाइलें ढूंढते समय,
$(rlocationpath ...)का इस्तेमाल करें. इसके अलावा,@bazel_tools//tools/{bash,cpp,java}/runfilesमें मौजूद रनफ़ाइल लाइब्रेरी में से किसी एक का इस्तेमाल करें. अगर आपकोrules_fooके लिए रनफ़ाइलें ढूंढनी हैं, तो@rules_foo//foo/runfilesमें मौजूद रनफ़ाइल लाइब्रेरी में से किसी एक का इस्तेमाल करें. - जब किसी बाहरी टूल, जैसे कि IDE या भाषा सर्वर से Bazel के साथ इंटरैक्ट किया जाता है, तब
bazel mod dump_repo_mappingकमांड का इस्तेमाल करके, रिपॉज़िटरी के किसी सेट के लिए, दिखने वाले नामों से कैननिकल नामों की मैपिंग पाएं.
मॉड्यूल एक्सटेंशन, मॉड्यूल के दिखने वाले स्कोप में अतिरिक्त रिपॉज़िटरी भी जोड़ सकते हैं.