एक्सटर्नल डिपेंडेंसी के बारे में खास जानकारी

Bazel, एक्सटर्नल डिपेंडेंसी, सोर्स फ़ाइलों (टेक्स्ट और बाइनरी, दोनों) के साथ काम करता है. इनका इस्तेमाल आपके बिल्ड में किया जाता है. ये आपके वर्कस्पेस से नहीं होती हैं. उदाहरण के लिए, ये GitHub रिपॉज़िटरी में होस्ट किया गया कोई नियम सेट, Maven आर्टफ़ैक्ट या आपके मौजूदा वर्कस्पेस से बाहर, आपकी लोकल मशीन पर मौजूद कोई डायरेक्ट्री हो सकती हैं.

Bazel 6.0 से, Bazel के साथ एक्सटर्नल डिपेंडेंसी मैनेज करने के दो तरीके हैं: पहला, रिपॉज़िटरी पर फ़ोकस करने वाला पुराना WORKSPACE सिस्टम और दूसरा, मॉड्यूल पर फ़ोकस करने वाला नया MODULE.bazel सिस्टम. इसे Bzlmod कोडनेम दिया गया है, और यह --enable_bzlmod फ़्लैग के साथ काम करता है. इन दोनों सिस्टम का इस्तेमाल एक साथ किया जा सकता है. हालांकि, Bazel की आने वाली रिलीज़ में, Bzlmod, WORKSPACE सिस्टम की जगह लेगा. माइग्रेट करने का तरीका जानने के लिए, Bzlmod माइग्रेशन गाइड देखें.

इस दस्तावेज़ में, Bazel में एक्सटर्नल डिपेंडेंसी मैनेजमेंट से जुड़े कॉन्सेप्ट के बारे में बताया गया है. इसके बाद, दोनों सिस्टम के बारे में ज़्यादा जानकारी दी गई है.

कॉन्सेप्ट

रिपॉज़िटरी

यह एक डायरेक्ट्री होती है, जिसमें WORKSPACE या WORKSPACE.bazel फ़ाइल होती है. इसमें Bazel बिल्ड में इस्तेमाल की जाने वाली सोर्स फ़ाइलें होती हैं. इसे अक्सर सिर्फ़ रिपो कहा जाता है.

मुख्य रिपॉज़िटरी

यह वह रिपॉज़िटरी होती है जिसमें Bazel का मौजूदा कमांड चलाया जा रहा है.

Workspace

यह वह एनवायरमेंट होता है जिसे एक ही मुख्य रिपॉज़िटरी में चलाए गए Bazel के सभी कमांड शेयर करते हैं.

ध्यान दें कि पहले "रिपॉज़िटरी" और "वर्कस्पेस" के कॉन्सेप्ट को एक ही माना जाता था. "वर्कस्पेस" शब्द का इस्तेमाल अक्सर मुख्य रिपॉज़िटरी के लिए किया जाता था. कभी-कभी इसे "रिपॉज़िटरी" के समानार्थी के तौर पर भी इस्तेमाल किया जाता था.

कैननिकल रिपॉज़िटरी का नाम

यह वह कैननिकल नाम होता है जिससे किसी रिपॉज़िटरी को ऐक्सेस किया जा सकता है. किसी वर्कस्पेस के संदर्भ में, हर रिपॉज़िटरी का एक कैननिकल नाम होता है. किसी रिपो में मौजूद टारगेट जिसका कैननिकल नाम canonical_name है, उसे @@canonical_name//pac/kage:target लेबल से ऐक्सेस किया जा सकता है. ध्यान दें कि इसमें दो @ का इस्तेमाल किया गया है.

मुख्य रिपॉज़िटरी का कैननिकल नाम हमेशा खाली स्ट्रिंग होता है.

रिपॉज़िटरी का नाम

यह वह नाम होता है जिससे किसी दूसरी रिपो के संदर्भ में, किसी रिपॉज़िटरी को ऐक्सेस किया जा सकता है. इसे किसी रिपो का "निकनेम" माना जा सकता है: कैननिकल नाम michael वाली रिपो का नाम, alice रिपो के संदर्भ में mike हो सकता है. वहीं, bob रिपो के संदर्भ में, इसका नाम mickey हो सकता है. इस मामले में, michael में मौजूद किसी टारगेट को लेबल @mike//pac/kage:target से alice के संदर्भ में ऐक्सेस किया जा सकता है. ध्यान दें कि इसमें एक @ का इस्तेमाल किया गया है.

इसके उलट, इसे रिपॉज़िटरी मैपिंग के तौर पर समझा जा सकता है: हर रिपो "रिपॉज़िटरी के नाम" से "कैननिकल रिपॉज़िटरी के नाम" तक की मैपिंग बनाए रखती है.

रिपॉज़िटरी का नियम

यह रिपॉज़िटरी की डेफ़िनिशन का स्कीमा होता है. इससे Bazel को पता चलता है कि किसी रिपॉज़िटरी को कैसे तैयार किया जाए. उदाहरण के लिए, यह "किसी यूआरएल से zip संग्रह डाउनलोड करें और उसे एक्सट्रैक्ट करें", "किसी Maven आर्टफ़ैक्ट को फ़ेच करें और उसे java_import टारगेट के तौर पर उपलब्ध कराएं" या सिर्फ़ "किसी लोकल डायरेक्ट्री को सिमलंक करें" हो सकता है. हर रिपो को, सही संख्या में आर्ग्युमेंट के साथ रिपो के नियम को कॉल करके तय किया जाता है.

रिपॉज़िटरी के अपने नियम लिखने के तरीके के बारे में ज़्यादा जानने के लिए, रिपॉज़िटरी के नियम देखें.

सबसे आम रिपो के नियम, http_archive और local_repository हैं. http_archive नियम, किसी यूआरएल से संग्रह डाउनलोड करता है और उसे एक्सट्रैक्ट करता है. वहीं, local_repository नियम, किसी लोकल डायरेक्ट्री को सिमलंक करता है, जो पहले से ही Bazel रिपॉज़िटरी है.

रिपॉज़िटरी को फ़ेच करना

यह, रिपो के नियम को चलाकर, किसी रिपो को लोकल डिस्क पर उपलब्ध कराने की कार्रवाई होती है. किसी वर्कस्पेस में तय की गई रिपो, फ़ेच किए जाने से पहले लोकल डिस्क पर उपलब्ध नहीं होती हैं.

आम तौर पर, Bazel किसी रिपो को सिर्फ़ तब फ़ेच करता है, जब उसे रिपो से किसी चीज़ की ज़रूरत होती है और रिपो को पहले से फ़ेच नहीं किया गया होता है. अगर रिपो को पहले से फ़ेच किया गया है, तो Bazel उसे सिर्फ़ तब फिर से फ़ेच करता है, जब उसकी डेफ़िनिशन में बदलाव हुआ हो.

डायरेक्ट्री का लेआउट

फ़ेच किए जाने के बाद, रिपो को आउटपुट बेस में, external सबडायरेक्ट्री में, उसके कैननिकल नाम से देखा जा सकता है.

कैननिकल नाम canonical_name वाली रिपो का कॉन्टेंट देखने के लिए, यह कमांड चलाएं:

ls $(bazel info output_base)/external/ canonical_name 

Bzlmod की मदद से एक्सटर्नल डिपेंडेंसी मैनेज करना

एक्सटर्नल डिपेंडेंसी के नए सबसिस्टम, Bzlmod, रिपो की डेफ़िनिशन के साथ सीधे काम नहीं करता. इसके बजाय, यह मॉड्यूल से डिपेंडेंसी ग्राफ़ बनाता है, ग्राफ़ पर एक्सटेंशन चलाता है, और उसके मुताबिक रिपो तय करता है.

Bazel मॉड्यूल , Bazel का एक ऐसा प्रोजेक्ट होता है जिसके कई वर्शन हो सकते हैं. इनमें से हर वर्शन, उन अन्य मॉड्यूल के बारे में मेटाडेटा पब्लिश करता है जिन पर वह निर्भर करता है. किसी मॉड्यूल की रिपो रूट में, WORKSPACE फ़ाइल के बगल में, 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")

किसी मॉड्यूल को सिर्फ़ अपनी डायरेक्ट डिपेंडेंसी की सूची बनानी चाहिए. Bzlmod, Bazel रजिस्ट्री में इन्हें ढूंढता है. डिफ़ॉल्ट रूप से, यह Bazel Central Registry होती है. रजिस्ट्री, डिपेंडेंसी की MODULE.bazel फ़ाइलें उपलब्ध कराती है. इससे Bazel, वर्शन रिज़ॉल्यूशन करने से पहले, ट्रांज़िटिव डिपेंडेंसी का पूरा ग्राफ़ ढूंढ पाता है.

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

मॉड्यूल, टैग नाम का कस्टम डेटा भी तय कर सकते हैं. मॉड्यूल रिज़ॉल्यूशन के बाद, मॉड्यूल एक्सटेंशन इनका इस्तेमाल, अतिरिक्त रिपो तय करने के लिए करते हैं. इन एक्सटेंशन में, रिपो के नियमों जैसी क्षमताएं होती हैं. इससे ये फ़ाइल I/O और नेटवर्क अनुरोध भेजने जैसी कार्रवाइयां कर पाते हैं. अन्य चीज़ों के अलावा, ये Bazel मॉड्यूल से बने डिपेंडेंसी ग्राफ़ का पालन करते हुए, Bazel को अन्य पैकेज मैनेजमेंट सिस्टम के साथ इंटरैक्ट करने की अनुमति देते हैं.

WORKSPACE की मदद से रिपो तय करना

पहले, WORKSPACE (या WORKSPACE.bazel) फ़ाइल में रिपो तय करके, एक्सटर्नल डिपेंडेंसी मैनेज की जा सकती थीं. इस फ़ाइल का सिंटैक्स, BUILD फ़ाइलों जैसा होता है. इसमें बिल्ड के नियमों के बजाय, रिपो के नियमों का इस्तेमाल किया जाता है.

WORKSPACE फ़ाइल में, http_archive रिपो के नियम का इस्तेमाल करने का उदाहरण यहां दिया गया है:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "foo",
    urls = ["https://example.com/foo.zip"],
    sha256 = "c9526390a7cd420fdcec2988b4f3626fe9c5b51e2959f685e8f4d170d1a9bd96",
)

इस स्निपेट में, foo कैननिकल नाम वाली रिपो तय की गई है. WORKSPACE सिस्टम में, डिफ़ॉल्ट रूप से, किसी रिपो का कैननिकल नाम, अन्य सभी रिपो के लिए उसका नाम भी होता है.

WORKSPACE सिस्टम की कमियां

WORKSPACE सिस्टम को लॉन्च किए जाने के बाद से, उपयोगकर्ताओं ने कई समस्याएं बताई हैं. इनमें ये शामिल हैं:

  • Bazel, किसी भी डिपेंडेंसी की WORKSPACE फ़ाइलों का आकलन नहीं करता. इसलिए, डायरेक्ट डिपेंडेंसी के अलावा, सभी ट्रांज़िटिव डिपेंडेंसी को मुख्य रिपो की WORKSPACE फ़ाइल में तय करना ज़रूरी है.
  • इससे बचने के लिए, प्रोजेक्ट ने "deps.bzl" पैटर्न अपनाया है. इसमें वे एक मैक्रो तय करते हैं, जो कई रिपो तय करता है. साथ ही, उपयोगकर्ताओं से अपनी WORKSPACE फ़ाइलों में इस मैक्रो को कॉल करने के लिए कहा जाता है.
    • इससे जुड़ी समस्याएं भी हैं: मैक्रो, अन्य .bzl फ़ाइलें load नहीं कर सकते. इसलिए, इन प्रोजेक्ट को अपनी ट्रांज़िटिव डिपेंडेंसी, इस "deps" मैक्रो में तय करनी होती है. इसके अलावा, इस समस्या से बचने के लिए, उपयोगकर्ता को कई लेयर वाले "deps" मैक्रो को कॉल करना होता है.
    • Bazel, WORKSPACE फ़ाइल का आकलन क्रम से करता है. इसके अलावा, डिपेंडेंसी, यूआरएल के साथ http_archive का इस्तेमाल करके तय की जाती हैं. इनमें वर्शन की कोई जानकारी नहीं होती. इसका मतलब है कि डायमंड डिपेंडेंसी (A, B और C पर निर्भर करता है; B और C, दोनों D के अलग-अलग वर्शन पर निर्भर करते हैं) के मामले में, वर्शन रिज़ॉल्यूशन करने का कोई भरोसेमंद तरीका नहीं है.

WORKSPACE की कमियों की वजह से, Bazel की आने वाली रिलीज़ में, Bzlmod, पुराने WORKSPACE सिस्टम की जगह लेगा. Bzlmod पर माइग्रेट करने का तरीका जानने के लिए, कृपया Bzlmod माइग्रेशन गाइड पढ़ें.