Bazel, बाहरी डिपेंडेंसी के साथ-साथ सोर्स फ़ाइलों (टेक्स्ट और बाइनरी, दोनों) के साथ काम करता है. ये फ़ाइलें, आपके बिल्ड में इस्तेमाल की जाती हैं और आपके वर्कस्पेस से नहीं होती हैं. उदाहरण के लिए, वे GitHub repo में होस्ट किया गया कोई नियम सेट, Maven आर्टफ़ैक्ट या आपकी लोकल मशीन पर मौजूद कोई ऐसी डायरेक्ट्री हो सकती हैं जो आपके मौजूदा वर्कस्पेस से बाहर हो.
Bazel 6.0 के मुताबिक, Bazel के साथ बाहरी डिपेंडेंसी मैनेज करने के दो तरीके हैं:
पहला, रिपॉज़िटरी पर फ़ोकस करने वाला WORKSPACE
सिस्टम और
दूसरा, मॉड्यूल पर फ़ोकस करने वाला नया MODULE.bazel
सिस्टम. इसे Bzlmod के नाम से जाना जाता है और यह --enable_bzlmod
फ़्लैग के साथ चालू होता है. इन दोनों सिस्टम का इस्तेमाल एक साथ किया जा सकता है. हालांकि, Bazel के आने वाले वर्शन में WORKSPACE
सिस्टम की जगह Bzlmod का इस्तेमाल किया जाएगा. माइग्रेट करने का तरीका जानने के लिए, Bzlmod माइग्रेशन गाइड देखें.
इस दस्तावेज़ में, Bazel में बाहरी डिपेंडेंसी मैनेज करने से जुड़े कॉन्सेप्ट के बारे में बताया गया है. इसके बाद, दोनों सिस्टम के बारे में ज़्यादा जानकारी दी गई है.
कॉन्सेप्ट
रिपॉज़िटरी
एक डायरेक्ट्री ट्री, जिसके रूट में बाउंड्री मार्कर फ़ाइल होती है. इसमें ऐसी सोर्स फ़ाइलें होती हैं जिनका इस्तेमाल Bazel बिल्ड में किया जा सकता है. इसे अक्सर छोटा करके सिर्फ़ repo कहा जाता है.
रेपो बाउंड्री मार्कर फ़ाइल MODULE.bazel
(यह बताती है कि यह रेपो, Bazel मॉड्यूल को दिखाता है), REPO.bazel
(नीचे देखें) या लेगसी कॉन्टेक्स्ट में, WORKSPACE
या WORKSPACE.bazel
हो सकती है. किसी भी रेपो बाउंड्री मार्कर फ़ाइल से, रेपो की बाउंड्री का पता चलेगा. इस तरह की कई फ़ाइलें, किसी डायरेक्ट्री में एक साथ मौजूद हो सकती हैं.
मुख्य रिपॉज़िटरी
वह रिपॉज़िटरी जिसमें Bazel का मौजूदा कमांड चलाया जा रहा है.
मुख्य रिपॉज़िटरी के रूट को वर्कस्पेस रूट भी कहा जाता है.
Workspace
Bazel के सभी कमांड से शेयर किया गया एनवायरमेंट, एक ही मुख्य रिपॉज़िटरी में चलता है. इसमें मुख्य रेपो और तय की गई सभी बाहरी रेपो का सेट शामिल होता है.
ध्यान दें कि पहले "रिपॉज़िटरी" और "वर्कस्पेस" के कॉन्सेप्ट को एक ही माना जाता था. "वर्कस्पेस" शब्द का इस्तेमाल अक्सर मुख्य रिपॉज़िटरी के लिए किया जाता था. कभी-कभी इसे "रिपॉज़िटरी" के पर्यायवाची के तौर पर भी इस्तेमाल किया जाता था.
कैननिकल रिपॉज़िटरी का नाम
वह कैननिकल नाम जिससे किसी रिपॉज़िटरी को ऐक्सेस किया जा सकता है. किसी वर्कस्पेस के कॉन्टेक्स्ट में, हर रिपॉज़िटरी का एक ही कैननिकल नाम होता है. किसी रिपॉज़िटरी में मौजूद टारगेट, जिसका कैननिकल नाम canonical_name
है उसे @@canonical_name//pac/kage:target
लेबल से ऐक्सेस किया जा सकता है. ध्यान दें कि इसमें दो @
हैं.
मुख्य रिपॉज़िटरी का कैननिकल नाम हमेशा खाली स्ट्रिंग होता है.
रिपॉज़िटरी का नाम
किसी अन्य रेपो के संदर्भ में, वह नाम जिससे किसी रेपो को ऐक्सेस किया जा सकता है.
इसे किसी रिपॉज़िटरी का "निकनेम" माना जा सकता है: कैननिकल नाम michael
वाली रिपॉज़िटरी का नाम, रिपॉज़िटरी alice
के संदर्भ में mike
हो सकता है. हालांकि, रिपॉज़िटरी bob
के संदर्भ में इसका नाम mickey
हो सकता है. इस मामले में, michael
में मौजूद किसी टारगेट को alice
के कॉन्टेक्स्ट में लेबल @mike//pac/kage:target
से ऐक्सेस किया जा सकता है. ध्यान दें कि यहां सिर्फ़ एक @
है.
इसके उलट, इसे रिपॉज़िटरी मैपिंग के तौर पर समझा जा सकता है: हर रिपो, "रिपो का नाम" से "कैननिकल रिपो का नाम" तक की मैपिंग बनाए रखता है.
रिपॉज़िटरी का नियम
डेटाबेस की परिभाषाओं के लिए स्कीमा. इससे Bazel को यह पता चलता है कि डेटाबेस को कैसे बनाया जाए. उदाहरण के लिए, यह "किसी यूआरएल से ज़िप संग्रह डाउनलोड करें और उसे निकालें", "किसी Maven आर्टफ़ैक्ट को फ़ेच करें और उसे java_import
टारगेट के तौर पर उपलब्ध कराएं" या सिर्फ़ "किसी स्थानीय डायरेक्ट्री को सिमलंक करें" हो सकता है. हर रिपॉज़िटरी को, सही संख्या में आर्ग्युमेंट के साथ रिपॉज़िटरी के नियम को कॉल करके तय किया जाता है.
अपने रिपॉज़िटरी के नियम लिखने के बारे में ज़्यादा जानने के लिए, रिपॉज़िटरी के नियम देखें.
सबसे ज़्यादा इस्तेमाल किए जाने वाले repo नियम ये हैं: http_archive
, जो किसी यूआरएल से संग्रह डाउनलोड करता है और उसे निकालता है. इसके अलावा, local_repository
, जो पहले से मौजूद Bazel रिपॉज़िटरी वाली लोकल डायरेक्ट्री को सिमलंक करता है.
किसी रिपॉज़िटरी को फ़ेच करना
किसी repo से जुड़े repo के नियम को लागू करके, repo को लोकल डिस्क पर उपलब्ध कराने की कार्रवाई. वर्कस्पेस में तय की गई रिपॉज़िटरी, फ़ेच किए जाने से पहले लोकल डिस्क पर उपलब्ध नहीं होती हैं.
आम तौर पर, Bazel किसी repo को सिर्फ़ तब फ़ेच करता है, जब उसे repo से किसी चीज़ की ज़रूरत होती है और repo को पहले से फ़ेच नहीं किया गया होता है. अगर रेपो को पहले ही फ़ेच किया जा चुका है, तो Bazel इसे सिर्फ़ तब फिर से फ़ेच करता है, जब इसकी डेफ़िनिशन में बदलाव हुआ हो.
fetch
कमांड का इस्तेमाल, किसी रिपॉज़िटरी, टारगेट या सभी ज़रूरी रिपॉज़िटरी के लिए प्री-फ़ेच शुरू करने के लिए किया जा सकता है, ताकि कोई भी बिल्ड किया जा सके. इस सुविधा की मदद से, --nofetch
विकल्प का इस्तेमाल करके ऑफ़लाइन बिल्ड बनाए जा सकते हैं.
--fetch
विकल्प का इस्तेमाल, नेटवर्क ऐक्सेस को मैनेज करने के लिए किया जाता है. इसकी डिफ़ॉल्ट वैल्यू, सही है.
हालांकि, अगर इसे गलत (--nofetch
) पर सेट किया जाता है, तो कमांड, डिपेंडेंसी के किसी भी कैश मेमोरी वर्शन का इस्तेमाल करेगी. अगर कोई भी वर्शन मौजूद नहीं है, तो कमांड काम नहीं करेगी.
डेटा फ़ेच करने की प्रोसेस को कंट्रोल करने के बारे में ज़्यादा जानने के लिए, डेटा फ़ेच करने के विकल्प देखें.
डायरेक्ट्री का लेआउट
फ़ेच किए जाने के बाद, रिपो को आउटपुट बेस में external
सबडायरेक्ट्री में, इसके कैननिकल नाम से देखा जा सकता है.
कैननिकल नाम canonical_name
के साथ रिपॉज़िटरी का कॉन्टेंट देखने के लिए, यह कमांड चलाएं:
ls $(bazel info output_base)/external/ canonical_name
REPO.bazel फ़ाइल
REPO.bazel
फ़ाइल का इस्तेमाल, डायरेक्ट्री ट्री की सबसे ऊपरी सीमा को मार्क करने के लिए किया जाता है. यह सीमा, किसी रेपो को बनाती है. इसे रिपॉज़िटरी की बाउंड्री फ़ाइल के तौर पर इस्तेमाल करने के लिए, इसमें कुछ भी शामिल करने की ज़रूरत नहीं होती. हालांकि, इसका इस्तेमाल रिपॉज़िटरी में मौजूद सभी बिल्ड टारगेट के लिए, कुछ सामान्य एट्रिब्यूट तय करने के लिए भी किया जा सकता है.
REPO.bazel
फ़ाइल का सिंटैक्स, BUILD
फ़ाइलों के जैसा ही होता है. हालांकि, इसमें load
स्टेटमेंट इस्तेमाल नहीं किए जा सकते. साथ ही, इसमें सिर्फ़ एक फ़ंक्शन, repo()
उपलब्ध होता है. repo()
, BUILD
फ़ाइलों में मौजूद package()
फ़ंक्शन के जैसे ही आर्ग्युमेंट लेता है. वहीं, package()
पैकेज में मौजूद सभी बिल्ड टारगेट के लिए सामान्य एट्रिब्यूट तय करता है. इसी तरह, repo()
रिपो में मौजूद सभी बिल्ड टारगेट के लिए सामान्य एट्रिब्यूट तय करता है.
उदाहरण के लिए, अपनी रिपॉज़िटरी में मौजूद सभी टारगेट के लिए एक सामान्य लाइसेंस तय किया जा सकता है. इसके लिए, आपको यह REPO.bazel
फ़ाइल बनानी होगी:
repo(
default_package_metadata = ["//:my_license"],
)
Bzlmod की मदद से बाहरी डिपेंडेंसी मैनेज करना
Bzlmod, बाहरी डिपेंडेंसी का नया सबसिस्टम है. यह सीधे तौर पर repo definitions के साथ काम नहीं करता. इसके बजाय, यह मॉड्यूल से डिपेंडेंसी ग्राफ़ बनाता है. साथ ही, ग्राफ़ के ऊपर एक्सटेंशन चलाता है और उसके हिसाब से रिपॉज़िटरी तय करता है.
Bazel मॉड्यूल एक Bazel प्रोजेक्ट होता है. इसके कई वर्शन हो सकते हैं. हर वर्शन, उन अन्य मॉड्यूल के बारे में मेटाडेटा पब्लिश करता है जिन पर वह निर्भर होता है. किसी मॉड्यूल के लिए, उसके रेपो रूट में 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")
किसी मॉड्यूल को सिर्फ़ अपनी डायरेक्ट डिपेंडेंसी की सूची बनानी चाहिए. Bzlmod, Bazel रजिस्ट्री में इनकी खोज करता है. डिफ़ॉल्ट रूप से, यह Bazel Central Registry होती है. रजिस्ट्री, डिपेंडेंसी की MODULE.bazel
फ़ाइलें उपलब्ध कराती है. इससे Bazel को वर्शन रिज़ॉल्यूशन करने से पहले, पूरे ट्रांज़िटिव डिपेंडेंसी ग्राफ़ का पता लगाने में मदद मिलती है.
वर्शन तय होने के बाद, Bazel हर मॉड्यूल के लिए एक वर्शन चुनता है. इसके बाद, Bazel हर मॉड्यूल के लिए रेपो को तय करने का तरीका जानने के लिए, रजिस्ट्री से फिर से सलाह लेता है. ज़्यादातर मामलों में, http_archive
का इस्तेमाल किया जाता है.
मॉड्यूल, डेटा के कस्टम कॉम्पोनेंट भी तय कर सकते हैं. इन्हें टैग कहा जाता है. मॉड्यूल रिज़ॉल्यूशन के बाद, मॉड्यूल एक्सटेंशन इनका इस्तेमाल करते हैं, ताकि अतिरिक्त रिपॉज़िटरी तय की जा सकें. इन एक्सटेंशन में repo rules जैसी सुविधाएं होती हैं. इनकी मदद से, फ़ाइल I/O और नेटवर्क अनुरोध भेजने जैसी कार्रवाइयां की जा सकती हैं. इनकी मदद से, Bazel को अन्य पैकेज मैनेजमेंट सिस्टम के साथ इंटरैक्ट करने की अनुमति मिलती है. साथ ही, Bazel मॉड्यूल से बनाए गए डिपेंडेंसी ग्राफ़ का पालन किया जाता है.
Bzlmod पर बाहरी लिंक
- bazelbuild/examples में bzlmod के इस्तेमाल के उदाहरण
- Bazel की बाहरी डिपेंडेंसी को बेहतर बनाने से जुड़ा दस्तावेज़ (Bzlmod के डिज़ाइन से जुड़ा मूल दस्तावेज़)
- Bzlmod पर BazelCon 2021 की बातचीत
- Bazel Community Day में Bzlmod के बारे में बातचीत
WORKSPACE
की मदद से, रेपो को परिभाषित करें
पहले, WORKSPACE
(या WORKSPACE.bazel
) फ़ाइल में रेपो तय करके, बाहरी डिपेंडेंसी मैनेज की जा सकती थीं. इस फ़ाइल का सिंटैक्स, BUILD
फ़ाइलों के सिंटैक्स जैसा ही होता है. इसमें बिल्ड के नियमों के बजाय, रेपो के नियमों का इस्तेमाल किया जाता है.
नीचे दिया गया स्निपेट, WORKSPACE
फ़ाइल में http_archive
repo rule का इस्तेमाल करने का उदाहरण है:
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
सिस्टम की कमियां
WORKSPACE
सिस्टम को लॉन्च हुए कई साल हो चुके हैं. इस दौरान, उपयोगकर्ताओं ने कई समस्याएं बताई हैं. इनमें ये शामिल हैं:
- Bazel, किसी भी डिपेंडेंसी की
WORKSPACE
फ़ाइलों का आकलन नहीं करता. इसलिए, सभी ट्रांज़िटिव डिपेंडेंसी को मुख्य रेपो कीWORKSPACE
फ़ाइल में तय किया जाना चाहिए. इसके अलावा, डायरेक्ट डिपेंडेंसी को भी तय किया जाना चाहिए. - इससे बचने के लिए, प्रोजेक्ट में "deps.bzl" पैटर्न का इस्तेमाल किया जाता है. इसमें वे एक मैक्रो तय करते हैं, जो कई रिपॉज़िटरी तय करता है. साथ ही, उपयोगकर्ताओं से इस मैक्रो को अपनी
WORKSPACE
फ़ाइलों में कॉल करने के लिए कहता है.- इसकी अपनी समस्याएं हैं: मैक्रो,
load
अन्य.bzl
फ़ाइलें नहीं कर सकते. इसलिए, इन प्रोजेक्ट को इस "deps" मैक्रो में अपनी ट्रांज़िटिव डिपेंडेंसी तय करनी होती है. इसके अलावा, इस समस्या को हल करने के लिए, उपयोगकर्ता को कई लेयर वाले "deps" मैक्रो को कॉल करना होता है. - Bazel,
WORKSPACE
फ़ाइल का आकलन क्रम से करता है. इसके अलावा, यूआरएल के साथhttp_archive
का इस्तेमाल करके डिपेंडेंसी तय की जाती हैं. इसमें वर्शन की कोई जानकारी नहीं होती. इसका मतलब है कि डायमंड डिपेंडेंसी (A
,B
औरC
पर निर्भर करता है;B
औरC
, दोनोंD
के अलग-अलग वर्शन पर निर्भर करते हैं) के मामले में, वर्शन रिज़ॉल्यूशन करने का कोई भरोसेमंद तरीका नहीं है.
- इसकी अपनी समस्याएं हैं: मैक्रो,
WORKSPACE की कमियों की वजह से, Bzlmod आने वाले समय में Bazel की रिलीज़ में, लेगसी WORKSPACE सिस्टम की जगह लेगा. Bzlmod पर माइग्रेट करने का तरीका जानने के लिए, कृपया Bzlmod माइग्रेशन गाइड पढ़ें.