अक्सर पूछे जाने वाले सवाल

इस पेज पर, Bazel में बाहरी डिपेंडेंसी के बारे में अक्सर पूछे जाने वाले कुछ सवालों के जवाब दिए गए हैं.

MODULE.bazel

मुझे Bazel मॉड्यूल का वर्शन कैसे तय करना चाहिए?

सोर्स आर्काइव MODULE.bazel में module डायरेक्टिव के साथ version सेट करने के कई नुकसान हो सकते हैं. साथ ही, इससे अनचाहे साइड इफ़ेक्ट भी हो सकते हैं. इसलिए, इसे सावधानी से मैनेज करना ज़रूरी है:

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

आम तौर पर, यह प्रोसेस ऑटोमेटेड होती है. उदाहरण के लिए, rules-template के उदाहरण के तौर पर, नियम रिपॉज़िटरी, रिलीज़ को BCR पर पब्लिश करने के लिए, bazel-contrib/publish-to-bcr publish.yaml GitHub Action का इस्तेमाल करती है. यह ऐक्शन, रिलीज़ वर्शन के साथ सोर्स आर्काइव MODULE.bazel के लिए पैच जनरेट करता है. यह पैच रजिस्ट्री में सेव किया जाता है और Bazel की बाहरी डिपेंडेंसी रिज़ॉल्यूशन के दौरान, मॉड्यूल फ़ेच किए जाने पर लागू होता है.

इस तरह, रजिस्ट्री में मौजूद रिलीज़ में वर्शन को रिलीज़ किए गए वर्शन पर सही तरीके से सेट किया जाएगा. इसलिए, bazel_dep, single_version_override और multiple_version_override उम्मीद के मुताबिक काम करेंगे. साथ ही, रजिस्ट्री से बाहर के तरीके से ओवरराइड करने पर होने वाली संभावित समस्याओं से बचा जा सकेगा. ऐसा इसलिए, क्योंकि सोर्स आर्काइव में वर्शन डिफ़ॉल्ट वैल्यू ('') होगा, जिसे हमेशा सही तरीके से हैंडल किया जाएगा. यह डिफ़ॉल्ट वर्शन वैल्यू है. साथ ही, सॉर्ट करते समय यह उम्मीद के मुताबिक काम करेगा. खाली स्ट्रिंग को सबसे नए वर्शन के तौर पर माना जाता है.

मुझे कंपैटिबिलिटी लेवल कब बढ़ाना चाहिए?

Bazel मॉड्यूल का compatibility_level उसी कमिट में बढ़ाया जाना चाहिए जिसमें पुराने वर्शन के साथ काम न करने वाला ("ब्रेकिंग") बदलाव किया गया हो.

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

इसलिए, compatibility_level को बार-बार बढ़ाने से, काम में काफ़ी रुकावट आ सकती है. इसलिए, ऐसा न करने का सुझाव दिया जाता है. इस स्थिति से बचने के लिए, compatibility_level को सिर्फ़ तब बढ़ाया जाना चाहिए, जब ब्रेकिंग बदलाव से ज़्यादातर इस्तेमाल के मामलों पर असर पड़ता हो और उसे माइग्रेट करना और/या वर्कअराउंड करना आसान न हो.

MODULE.bazel, load को क्यों सपोर्ट नहीं करता?

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

MODULE.bazel में loads के लिए अनुरोध करने वाले लोगों की दिलचस्पी आम तौर पर कुछ इस्तेमाल के मामलों में होती है. इन्हें loads के बिना भी हल किया जा सकता है:

  • यह पक्का करना कि MODULE.bazel में दिया गया वर्शन, कहीं और सेव किए गए बिल्ड मेटाडेटा के मुताबिक हो. उदाहरण के लिए, .bzl फ़ाइल में: इसे BUILD फ़ाइल से लोड की गई .bzl फ़ाइल में, native.module_version तरीके का इस्तेमाल करके हासिल किया जा सकता है.
  • बहुत बड़ी MODULE.bazel फ़ाइल को मैनेज किए जा सकने वाले सेक्शन में बांटना, खास तौर पर, मोनोरिपो के लिए: रूट मॉड्यूल, अपनी include डायरेक्टिव का इस्तेमाल करके अपनी MODULE.bazel फ़ाइल को कई सेगमेंट में बांट सकता है. इसी वजह से, हम MODULE.bazel फ़ाइलों में loads की अनुमति नहीं देते. साथ ही, रूट मॉड्यूल के अलावा अन्य मॉड्यूल में include का इस्तेमाल नहीं किया जा सकता.
  • पुराने WORKSPACE सिस्टम के उपयोगकर्ता, किसी रिपो को एलान करने और फिर जटिल लॉजिक को लागू करने के लिए, उस रिपो से तुरंत load करने की सुविधा को याद कर सकते हैं. इस सुविधा को मॉड्यूल एक्सटेंशन से बदल दिया गया है.

क्या मैं bazel_dep के लिए SemVer रेंज तय कर सकता/सकती हूं?

नहीं. npm और Cargo जैसे कुछ अन्य पैकेज मैनेजर, वर्शन रेंज (साफ़ तौर पर या इंप्लिसिट तौर पर) को सपोर्ट करते हैं. इसके लिए, अक्सर कंस्ट्रेंट सॉल्वर की ज़रूरत होती है. इससे उपयोगकर्ताओं के लिए आउटपुट का अनुमान लगाना मुश्किल हो जाता है. साथ ही, लॉकफ़ाइल के बिना वर्शन रिज़ॉल्यूशन को दोबारा नहीं किया जा सकता.

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

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

क्या मुझे bazel_dep के लिए, सबसे नया वर्शन अपने-आप मिल सकता है?

कुछ उपयोगकर्ता कभी-कभी bazel_dep(name = "foo", version = "latest") तय करने की सुविधा के बारे में पूछते हैं, ताकि डिपेंडेंसी का सबसे नया वर्शन अपने-आप मिल जाए. यह SemVer रेंज के बारे में पूछे गए सवाल जैसा ही है. इसका जवाब भी 'नहीं' है.

यहां हमारा सुझाव है कि इस काम के लिए ऑटोमेशन का इस्तेमाल किया जाए. उदाहरण के लिए, Renovate Bazel मॉड्यूल को सपोर्ट करता है.

कभी-कभी, यह सवाल पूछने वाले उपयोगकर्ता, असल में स्थानीय डेवलपमेंट के दौरान तेज़ी से दोहराने का तरीका ढूंढ रहे होते हैं. इसे a local_path_override का इस्तेमाल करके हासिल किया जा सकता है.

ये सभी use_repo क्यों हैं?

MODULE.bazel फ़ाइलों में मॉड्यूल एक्सटेंशन के इस्तेमाल के साथ, कभी-कभी बड़ा use_repo डायरेक्टिव भी होता है. उदाहरण के लिए, go_deps एक्सटेंशन से gazelle का सामान्य इस्तेमाल कुछ ऐसा दिख सकता है:

go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//:go.mod")
use_repo(
    go_deps,
    "com_github_gogo_protobuf",
    "com_github_golang_mock",
    "com_github_golang_protobuf",
    "org_golang_x_net",
    ...  # potentially dozens of lines...
)

लंबा use_repo डायरेक्टिव शायद ज़रूरत से ज़्यादा लग सकता है, क्योंकि इसकी जानकारी, रेफ़रंस वाली go.mod फ़ाइल में पहले से मौजूद होती है.

Bazel को इस use_repo डायरेक्टिव की ज़रूरत इसलिए होती है, क्योंकि यह मॉड्यूल एक्सटेंशन को लेज़ी तरीके से चलाता है. इसका मतलब है कि मॉड्यूल एक्सटेंशन सिर्फ़ तब चलता है, जब उसके नतीजे देखे जाते हैं. मॉड्यूल एक्सटेंशन का "आउटपुट", रिपो की परिभाषाएं होती हैं. इसका मतलब है कि हम मॉड्यूल एक्सटेंशन सिर्फ़ तब चलाते हैं, जब उसके ज़रिए तय किए गए किसी रिपो का अनुरोध किया जाता है. उदाहरण के लिए, ऊपर दिए गए उदाहरण में, अगर टारगेट @org_golang_x_net//:foo बनाया जाता है. हालांकि, हमें यह नहीं पता होता कि मॉड्यूल एक्सटेंशन कौनसे रिपो तय करेगा. यह जानकारी, उसे चलाने के बाद ही मिलती है. यहां use_repo डायरेक्टिव काम आता है. उपयोगकर्ता, Bazel को बता सकता है कि उसे एक्सटेंशन से कौनसे रिपो जनरेट होने की उम्मीद है. इसके बाद, Bazel सिर्फ़ तब एक्सटेंशन चलाएगा, जब इन खास रिपो का इस्तेमाल किया जाएगा.

इस use_repo डायरेक्टिव को बनाए रखने में मदद करने के लिए, मॉड्यूल एक्सटेंशन अपने लागू करने वाले फ़ंक्शन से extension_metadata ऑब्जेक्ट को वापस कर सकता है. उपयोगकर्ता, इन मॉड्यूल एक्सटेंशन के लिए use_repo डायरेक्टिव अपडेट करने के लिए, bazel mod tidy कमांड चला सकता है.

Bzlmod माइग्रेशन

MODULE.bazel या WORKSPACE में से किसे पहले ऐक्सेस किया जाता है?

जब --enable_bzlmod और --enable_workspace, दोनों सेट हों, तो यह जानना ज़रूरी है कि किस सिस्टम को पहले ऐक्सेस किया जाता है. इसका सीधा सा जवाब है कि MODULE.bazel (Bzlmod) को पहले ऐक्सेस किया जाता है.

इसका जवाब यह है कि "किसे पहले ऐक्सेस किया जाता है" यह सही सवाल नहीं है. इसके बजाय, सही सवाल यह है: कैननिकल नाम @@foo वाले रिपो के संदर्भ में, दिखने वाला रिपो नाम @bar किस रिपो को दिखाता है? इसके अलावा, @@base की रिपो मैपिंग क्या है?

दिखने वाले रिपो नामों (शुरुआत में सिर्फ़ एक @) वाले लेबल, उस संदर्भ के आधार पर अलग-अलग चीज़ों को रेफ़र कर सकते हैं जिनसे उन्हें रिज़ॉल्व किया जाता है. जब आपको @bar//:baz लेबल दिखता है और आपको यह जानना होता है कि यह असल में किस रिपो को दिखाता है, तो आपको सबसे पहले यह पता लगाना होगा कि संदर्भ रिपो क्या है. उदाहरण के लिए, अगर लेबल, @@foo रिपो में मौजूद किसी BUILD फ़ाइल में है, तो संदर्भ रिपो @@foo है.

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

  • अगर संदर्भ रिपो, मुख्य रिपो (@@) है, तो:
    1. अगर bar रूट मॉड्यूल की MODULE.bazel फ़ाइल (किसी भी bazel_dep, use_repo, module, use_repo_rule के ज़रिए) से जोड़ा गया दिखने वाला रिपो नाम है, तो @bar उस रिपो को दिखाता है जिसके बारे में MODULE.bazel फ़ाइल दावा करती है.
    2. इसके अलावा, अगर bar WORKSPACE में तय किया गया रिपो है (इसका मतलब है कि इसका कैननिकल नाम @@bar है), तो @bar, @@bar को दिखाता है.
    3. इसके अलावा, @bar किसी रिपो को दिखाता है @@[unknown repo 'bar' requested from @@]. इससे आखिर में गड़बड़ी होगी.
  • अगर संदर्भ रिपो, Bzlmod-world रिपो है (इसका मतलब है कि यह रूट मॉड्यूल के अलावा किसी अन्य Bazel मॉड्यूल से जुड़ा है या मॉड्यूल एक्सटेंशन से जनरेट किया गया है), तो यह सिर्फ़ Bzlmod-world रिपो को देखेगा. यह WORKSPACE-world रिपो को नहीं देखेगा.
    • खास तौर पर, इसमें रूट मॉड्यूल में non_module_deps-जैसे मॉड्यूल एक्सटेंशन या रूट मॉड्यूल में use_repo_rule इंस्टैंशिएशन में जोड़े गए सभी रिपो शामिल हैं.
  • अगर संदर्भ रिपो, WORKSPACE में तय किया गया है, तो:
    1. सबसे पहले, यह देखें कि संदर्भ रिपो की परिभाषा में, repo_mapping एट्रिब्यूट है या नहीं. अगर ऐसा है, तो सबसे पहले मैपिंग देखें. इसलिए, a repo defined with repo_mapping = {"@bar": "@baz"} के साथ तय किए गए रिपो के लिए, हम नीचे @baz देखेंगे.
    2. अगर bar रूट मॉड्यूल की MODULE.bazel फ़ाइल से जोड़ा गया दिखने वाला रिपो नाम है, तो @bar उस रिपो को दिखाता है जिसके बारे में MODULE.bazel फ़ाइल दावा करती है. (यह मुख्य रिपो के मामले में, पहले आइटम जैसा ही है.)
    3. इसके अलावा, @bar @@bar को दिखाता है. ज़्यादातर मामलों में, यह WORKSPACE में तय किए गए bar रिपो को दिखाएगा. अगर ऐसा कोई रिपो तय नहीं किया गया है, तो Bazel गड़बड़ी का मैसेज दिखाएगा.

ज़्यादा जानकारी के लिए:

  • Bzlmod-world रिपो (मुख्य रिपो को छोड़कर) सिर्फ़ Bzlmod-world रिपो को देखेंगे.
  • WORKSPACE-world रिपो (मुख्य रिपो सहित) सबसे पहले Bzlmod-world में रूट मॉड्यूल की परिभाषा देखेंगे. इसके बाद, WORKSPACE-world रिपो देखेंगे.

ध्यान दें कि Bazel की कमांड लाइन में मौजूद लेबल (Starlark फ़्लैग, लेबल-टाइप वाले फ़्लैग वैल्यू, और बिल्ड/टेस्ट टारगेट पैटर्न सहित) को, संदर्भ रिपो के तौर पर मुख्य रिपो के साथ माना जाता है.

अन्य

मैं ऑफ़लाइन बिल्ड कैसे तैयार करूं और उसे कैसे चलाऊं?

रिपो को पहले से फ़ेच करने के लिए, bazel fetch कमांड का इस्तेमाल करें. सिर्फ़ @foo रिपो को फ़ेच करने के लिए, --repo फ़्लैग (जैसे bazel fetch --repo @foo) का इस्तेमाल किया जा सकता है. इसे मुख्य रिपो के संदर्भ में रिज़ॉल्व किया जाता है. इसके बारे में ऊपर दिए गए सवाल में बताया गया है. इसके अलावा, @foo//:bar की सभी ट्रांज़िटिव डिपेंडेंसी को फ़ेच करने के लिए, टारगेट पैटर्न (जैसे bazel fetch @foo//:bar) का इस्तेमाल किया जा सकता है. यह bazel build --nobuild @foo//:bar के बराबर है.

यह पक्का करने के लिए कि बिल्ड के दौरान कोई फ़ेच न हो, --nofetch का इस्तेमाल करें. ज़्यादा सटीक तौर पर, इससे नॉन-लोकल रिपॉज़िटरी के नियम को चलाने की कोई भी कोशिश नाकाम हो जाती है.

अगर आपको रिपो फ़ेच करने और उन्हें स्थानीय तौर पर टेस्ट करने के लिए उनमें बदलाव करने हैं, तो bazel vendor कमांड का इस्तेमाल करें.

मैं एचटीटीपी प्रॉक्सी का इस्तेमाल कैसे करूं?

Bazel, http_proxy और HTTPS_PROXY एनवायरमेंट वैरिएबल को स्वीकार करता है. आम तौर पर, curl जैसे अन्य प्रोग्राम भी इन्हें स्वीकार करते हैं.

मैं Bazel को डुअल-स्टैक IPv4/IPv6 सेटअप में IPv6 को प्राथमिकता देने के लिए कैसे सेट करूं?

सिर्फ़ IPv6 वाली मशीनों पर, Bazel बिना किसी बदलाव के डिपेंडेंसी डाउनलोड कर सकता है. हालांकि, डुअल-स्टैक IPv4/IPv6 वाली मशीनों पर, Bazel, Java के जैसी ही प्रोसेस फ़ॉलो करता है. अगर IPv4 चालू है, तो उसे प्राथमिकता देता है. कुछ स्थितियों में, उदाहरण के लिए, जब IPv4 नेटवर्क, बाहरी पतों को रिज़ॉल्व/ऐक्सेस नहीं कर पाता है, तो इससे Network unreachable अपवाद और बिल्ड में गड़बड़ियां हो सकती हैं. ऐसे मामलों में, Bazel के व्यवहार को ओवरराइड किया जा सकता है, ताकि वह IPv6 को प्राथमिकता दे. इसके लिए, java.net.preferIPv6Addresses=true सिस्टम प्रॉपर्टी का इस्तेमाल करें. खास तौर पर:

क्या रिपो के नियमों को रिमोट एक्ज़ीक्यूशन के साथ, रिमोट तरीके से चलाया जा सकता है?

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

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

दूसरी वजह यह है कि Bazel को अक्सर डाउनलोड किए गए और एक्सट्रैक्ट किए गए आर्काइव में मौजूद BUILD फ़ाइलों की ज़रूरत होती है, ताकि लोडिंग और विश्लेषण किया जा सके. ये काम स्थानीय तौर पर किए जाते हैं .

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

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