इस पेज पर, Bazel में बाहरी डिपेंडेंसी के बारे में अक्सर पूछे जाने वाले कुछ सवालों के जवाब दिए गए हैं.
MODULE.bazel
MODULE.bazel में load
s क्यों काम नहीं करते?
डिपेंडेंसी रिज़ॉल्यूशन के दौरान, रेफ़र की गई सभी बाहरी डिपेंडेंसी की MODULE.bazel फ़ाइल को रजिस्ट्री से फ़ेच किया जाता है. इस चरण में, डिपेंडेंसी के सोर्स संग्रह अब तक फ़ेच नहीं किए गए हैं. इसलिए, अगर MODULE.bazel फ़ाइल load
को किसी दूसरी फ़ाइल से फ़ेच किया जाता है, तो Bazel के पास पूरे सोर्स संग्रह को फ़ेच किए बिना उस फ़ाइल को फ़ेच करने का कोई तरीका नहीं है. ध्यान दें कि MODULE.bazel फ़ाइल अपने-आप खास होती है, क्योंकि इसे सीधे तौर पर रजिस्ट्री पर होस्ट किया जाता है.
MODULE.bazel में load
के लिए पूछने वाले लोगों की दिलचस्पी, आम तौर पर इस्तेमाल के कुछ मामलों में होती है. इन मामलों को load
के बिना हल किया जा सकता है:
- यह पक्का करना कि MODULE.bazel में दिया गया वर्शन, कहीं और सेव किए गए बिल्ड मेटाडेटा से मेल खाता हो. उदाहरण के लिए, .bzl फ़ाइल में: ऐसा करने के लिए, BUILD फ़ाइल से लोड की गई .bzl फ़ाइल में,
native.module_version
तरीके का इस्तेमाल करें. - बहुत बड़ी MODULE.bazel फ़ाइल को मैनेज किए जा सकने वाले सेक्शन में बांटना. ऐसा खास तौर पर, मोनोरेपो के लिए किया जाता है: रूट मॉड्यूल, अपनी MODULE.bazel फ़ाइल को कई सेगमेंट में बांटने के लिए,
include
डायरेक्टिव का इस्तेमाल कर सकता है. इसी वजह से, हम MODULE.bazel फ़ाइलों मेंload
s की अनुमति नहीं देते.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 मॉड्यूल के साथ काम करता है.
कभी-कभी, यह सवाल पूछने वाले उपयोगकर्ता, लोकल डेवलपमेंट के दौरान तुरंत बदलाव करने का तरीका खोज रहे होते हैं. ऐसा करने के लिए, local_path_override
का इस्तेमाल करें.
ये सभी use_repo
क्यों हैं?
MODULE.bazel फ़ाइलों में मॉड्यूल एक्सटेंशन के इस्तेमाल के लिए, कभी-कभी बड़े use_repo
निर्देश का इस्तेमाल किया जाता है. उदाहरण के लिए, gazelle
से go_deps
एक्सटेंशन का सामान्य इस्तेमाल कुछ ऐसा दिख सकता है:
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
है.
इसके बाद, कॉन्टेक्स्ट रिपॉज़िटरी के हिसाब से, माइग्रेशन गाइड में मौजूद "रिपॉज़िटरी के दिखने की सेटिंग" टेबल का इस्तेमाल करके, यह पता लगाया जा सकता है कि कोई नाम किस रिपॉज़िटरी पर ले जाता है.
- अगर कॉन्टेक्स्ट रिपॉज़िटरी मुख्य रिपॉज़िटरी (
@@
) है, तो:- अगर
bar
, रूट मॉड्यूल की FILE.bazel फ़ाइल के ज़रिए दिखाया गया कोई ऐसा रिपॉज़िटरी नाम है जोbazel_dep
,use_repo
,module
,use_repo_rule
में से किसी भी फ़ाइल के ज़रिए दिखाया गया है, तो@bar
, FILE.bazel फ़ाइल में बताए गए रिपॉज़िटरी पर ले जाता है. - इसके अलावा, अगर
bar
, WORKSPACE में तय किया गया कोई रिपॉज़िटरी है (इसका मतलब है कि इसका कैननिकल नाम@@bar
है), तो@bar
,@@bar
पर रीडायरेक्ट करता है. - ऐसा न करने पर,
@bar
,@@[unknown repo 'bar' requested from @@]
जैसा कुछ बन जाएगा और आखिर में गड़बड़ी का मैसेज दिखेगा.
- अगर
- अगर कॉन्टेक्स्ट रिपॉज़िटरी, Bzlmod-world रिपॉज़िटरी है (यानी, यह किसी ग़ैर-रूट Bazel मॉड्यूल से जुड़ा है या मॉड्यूल एक्सटेंशन से जनरेट किया गया है), तो इसमें सिर्फ़ Bzlmod-world रिपॉज़िटरी दिखेंगी, न कि WORKSPACE-world रिपॉज़िटरी.
- खास तौर पर, इसमें रूट मॉड्यूल में
non_module_deps
जैसे मॉड्यूल एक्सटेंशन में जोड़े गए सभी रिपॉज़िटरी या रूट मॉड्यूल मेंuse_repo_rule
इंस्टैंशिएशन शामिल हैं.
- खास तौर पर, इसमें रूट मॉड्यूल में
- अगर कॉन्टेक्स्ट रिपॉज़िटरी को WORKSPACE में तय किया गया है, तो:
- सबसे पहले, देखें कि कॉन्टेक्स्ट रिपॉज़िटरी की परिभाषा में, मैजिकल
repo_mapping
एट्रिब्यूट है या नहीं. अगर ऐसा है, तो पहले मैपिंग देखें. इसलिए,repo_mapping = {"@bar": "@baz"}
से तय किए गए किसी रिपॉज़िटरी के लिए, हम नीचे@baz
देखेंगे. - अगर
bar
, रूट मॉड्यूल की MODULE.bazel फ़ाइल से शुरू किया गया कोई ऐसा रिपॉज़िटरी नाम है जो साफ़ तौर पर दिखता है, तो@bar
उसी पर सेट हो जाता है जिस पर MODULE.bazel फ़ाइल का दावा है. (यह मुख्य रिपॉज़िटरी केस में मौजूद आइटम 1 जैसा ही है.) - इसके अलावा,
@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 build --nobuild @foo//:bar
के बराबर है) को फ़ेच करने के लिए, टारगेट पैटर्न (bazel fetch @foo//:bar
की तरह) का इस्तेमाल किया जा सकता है.
पक्का करें कि बिल्ड के दौरान कोई फ़ेच न हो. इसके लिए, --nofetch
का इस्तेमाल करें. ज़्यादा सटीक तरीके से कहें, तो इससे किसी भी गैर-लोकल रिपॉज़िटरी नियम को चलाने की कोशिश विफल हो जाती है.
अगर आपको लोकल तौर पर टेस्ट करने के लिए, रिपॉज़िटरी फ़ेच करने और उनमें बदलाव करने हैं, तो bazel vendor
कमांड का इस्तेमाल करें.
मैं एचटीटीपी प्रॉक्सी का इस्तेमाल कैसे करूं?
Bazel, http_proxy
और HTTPS_PROXY
एनवायरमेंट वैरिएबल का इस्तेमाल करता है. आम तौर पर, इनका इस्तेमाल curl जैसे अन्य प्रोग्राम करते हैं.
मैं Bazel को ड्यूअल-स्टैक IPv4/IPv6 सेटअप में IPv6 को प्राथमिकता देने के लिए कैसे कहूं?
सिर्फ़ IPv6 वाली मशीनों पर, Bazel बिना किसी बदलाव के डिपेंडेंसी डाउनलोड कर सकता है. हालांकि, ड्यूअल-स्टैक IPv4/IPv6 मशीनों पर, Bazel उसी तरह के समझौते का पालन करता है जिस तरह Java करता है. अगर IPv4 चालू है, तो Bazel उसे प्राथमिकता देता है. कुछ मामलों में, जैसे कि जब IPv4 नेटवर्क, बाहरी पतों को हल नहीं कर पाता/उन तक नहीं पहुंच पाता, तो इससे Network
unreachable
अपवाद और बिल्ड में गड़बड़ियां हो सकती हैं. ऐसे मामलों में, java.net.preferIPv6Addresses=true
सिस्टम प्रॉपर्टी का इस्तेमाल करके, IPv6 को प्राथमिकता देने के लिए, Bazel के व्यवहार को बदला जा सकता है.
खास तौर पर:
--host_jvm_args=-Djava.net.preferIPv6Addresses=true
स्टार्टअप के विकल्प का इस्तेमाल करें. उदाहरण के लिए, अपनी.bazelrc
फ़ाइल में यह लाइन जोड़ें:startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true
इंटरनेट से कनेक्ट करने वाले जावा बिल्ड टारगेट (जैसे, इंटिग्रेशन टेस्ट के लिए) को चलाते समय,
--jvmopt=-Djava.net.preferIPv6Addresses=true
टूल के लिए इस्तेमाल किए जाने वाले फ़्लैग का इस्तेमाल करें. उदाहरण के लिए, अपनी.bazelrc
फ़ाइल में ये शामिल करें:build --jvmopt=-Djava.net.preferIPv6Addresses
अगर डिपेंडेंसी वर्शन को हल करने के लिए,
rules_jvm_external
का इस्तेमाल किया जा रहा है, तोCOURSIER_OPTS
एनवायरमेंट वैरिएबल में-Djava.net.preferIPv6Addresses=true
भी जोड़ें. इससे, Coursier के लिए JVM के विकल्प उपलब्ध कराए जा सकेंगे.
क्या रिमोट से चलाए जाने की सुविधा की मदद से, रिपॉज़िटरी के नियमों को कहीं से भी चलाया जा सकता है?
नहीं; या कम से कम, अभी नहीं. रिमोट से प्रोग्राम चलाने की सेवाओं का इस्तेमाल करके, अपने बिल्ड को तेज़ करने वाले उपयोगकर्ताओं को यह दिख सकता है कि अब भी रिपॉज़िटरी के नियम स्थानीय तौर पर लागू होते हैं. उदाहरण के लिए, http_archive
को पहले लोकल मशीन पर डाउनलोड किया जाएगा (अगर लागू हो, तो किसी भी लोकल डाउनलोड कैश मेमोरी का इस्तेमाल करके), फिर उसे निकाला जाएगा. इसके बाद, हर सोर्स फ़ाइल को इनपुट फ़ाइल के तौर पर, रिमोट इक्विज़िक्यूशन सेवा पर अपलोड किया जाएगा. यह पूछना स्वाभाविक है कि रिमोट से प्रोग्राम चलाने की सेवा, उस संग्रह को डाउनलोड और निकालकर, क्यों काम का राउंड ट्रिप बचाती है.
इसकी एक वजह यह है कि repo के नियम (और मॉड्यूल एक्सटेंशन) उन "स्क्रिप्ट" जैसे होते हैं जिन्हें Bazel खुद चलाता है. ज़रूरी नहीं है कि रिमोट एक्सीक्यूटर में Bazel इंस्टॉल हो.
एक और वजह यह है कि Bazel को अक्सर डाउनलोड किए गए और निकाले गए संग्रह में मौजूद BUILD फ़ाइलों की ज़रूरत होती है, ताकि लोडिंग और विश्लेषण किया जा सके. ये काम स्थानीय तौर पर किए जाते हैं.
इस समस्या को हल करने के लिए, शुरुआती तौर पर कुछ आइडिया हैं. इनमें, रिपॉज़िटरी के नियमों को बिल्ड रूल के तौर पर फिर से तैयार करना शामिल है. इससे, उन्हें रिमोट तौर पर चलाया जा सकता है. हालांकि, इससे आर्किटेक्चर से जुड़ी नई समस्याएं भी पैदा हो सकती हैं. उदाहरण के लिए, query
कमांड को कार्रवाइयां चलानी पड़ सकती हैं, जिससे उनके डिज़ाइन को मुश्किल बनाना पड़ सकता है.
इस विषय पर हुई पिछली चर्चा के बारे में ज़्यादा जानने के लिए, ऐसा तरीका जिससे उन रिपॉज़िटरी के साथ काम किया जा सके जिन्हें फ़ेच करने के लिए Bazel की ज़रूरत होती है देखें.