बैजल की मदद से कार्यक्रम बनाएं

इस पेज में Bazel के साथ प्रोग्राम बनाने, कमांड सिंटैक्स बनाने, और पैटर्न का टारगेट सिंटैक्स शामिल किया गया है.

क्विकस्टार्ट

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

bazel help
                             [Bazel release bazel version]
Usage: bazel command options ...

उपलब्ध निर्देश

  • analyze-profile: बिल्ड प्रोफ़ाइल के डेटा का विश्लेषण करता है.
  • aquery: पोस्ट-विश्लेषण कार्रवाई ग्राफ़ पर क्वेरी लागू करता है.
  • build: तय किए गए टारगेट बनाता है.
  • canonicalize-flags: बैजल फ़्लैग को कैननिकल बनाएं.
  • clean: आउटपुट फ़ाइलें हटा देता है और वैकल्पिक रूप से सर्वर को रोक देता है.
  • cquery: एक पोस्ट-विश्लेषण डिपेंडेंसी ग्राफ़ क्वेरी लागू करता है.
  • dump: बेज़ेल सर्वर प्रोसेस की अंदरूनी स्थिति को डंप करता है.
  • help: प्रिंट, निर्देशों या इंडेक्स करने में मदद करता है.
  • info: बैजल सर्वर के बारे में रनटाइम की जानकारी दिखाता है.
  • fetch: यह किसी टारगेट की सभी बाहरी डिपेंडेंसी फ़ेच करता है.
  • mobile-install: मोबाइल डिवाइस पर ऐप्लिकेशन इंस्टॉल करता है.
  • query: एक डिपेंडेंसी ग्राफ़ क्वेरी लागू करता है.
  • run: तय किए गए टारगेट को चलाता है.
  • shutdown: बैजल सर्वर को रोकता है.
  • test: तय किए गए टेस्ट टारगेट बनाता है और चलाता है.
  • version: Bazel की वर्शन जानकारी प्रिंट करता है.

सहायता पाना

  • bazel help command: command के लिए प्रिंट सहायता और विकल्प.
  • bazel helpstartup_options: JVM को होस्ट करने वाले JVM के लिए विकल्प.
  • bazel helptarget-syntax: टारगेट तय करने के लिए सिंटैक्स की जानकारी देता है.
  • bazel help info-keys: जानकारी वाले निर्देश का इस्तेमाल करने वाली कुंजियों की सूची दिखाता है.

bazel टूल कई फ़ंक्शन करता है, जिन्हें निर्देश कहा जाता है. सबसे ज़्यादा bazel build और bazel test इस्तेमाल किए जाते हैं. आप bazel help का उपयोग करके ऑनलाइन सहायता मैसेज ब्राउज़ कर सकते हैं.

एक टारगेट बनाना

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

बैजल के साथ प्रोग्राम बनाने के लिए, bazel build लिखें और फिर वह टारगेट लिखें, जिसे आप बनाना चाहते हैं.

bazel build //foo

//foo बनाने के लिए निर्देश जारी करने के बाद, आपको इससे मिलता-जुलता आउटपुट दिखेगा:

INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 9.905s, Critical Path: 3.25s
INFO: Build completed successfully, 6 total actions

सबसे पहले, Bazel आपके टारगेट पर निर्भर करने वाले ग्राफ़ में सभी पैकेज लोड करता है. इसमें एलान किए गए डिपेंडेंसी, टारगेट फ़ाइल की BUILD फ़ाइल में सीधे शामिल की गई फ़ाइलें, और BUILD फ़ाइलों में दी गई ट्रांज़िट डिपेंडेंसी फ़ाइलें शामिल हैं ज़रूरत के हिसाब से तय करते हैं. सभी निर्भरताओं की पहचान करने के बाद, बैजल सही होने के लिए उनका विश्लेषण करता है और बनाने की कार्रवाई करता है. आखिर में, बेज़ेल कंपाइलर और बिल्ड के दूसरे टूल लागू करता है.

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

बिल्ड के आखिर में, बैजल प्रिंट के अनुरोध किए गए थे कि वे सही तरीके से बनाए गए हैं या नहीं. अगर ऐसा किया गया है, तो वे आउटपुट फ़ाइलें कहां मिल सकती हैं. बिल्ड चलाने वाली स्क्रिप्ट इस आउटपुट को भरोसेमंद तरीके से पार्स कर सकती हैं; ज़्यादा जानकारी के लिए --show_result देखें.

अगर आप एक ही निर्देश फिर से लिखते हैं, तो बिल्ड ज़्यादा तेज़ी से खत्म होता है.

bazel build //foo
INFO: Analyzed target //foo:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
  bazel-bin/foo/foo
INFO: Elapsed time: 0.144s, Critical Path: 0.00s
INFO: Build completed successfully, 1 total action

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

कई टारगेट बनाना

बैजल बनाने के कई टारगेट दे सकता है. सामूहिक तौर पर, इन्हें टारगेट पैटर्न कहा जाता है. इस सिंटैक्स का इस्तेमाल build, test या query जैसे निर्देशों के लिए किया जाता है.

जहां लेबल का इस्तेमाल अलग-अलग टारगेट तय करने के लिए किया जाता है, जैसे कि BUILD फ़ाइलों में डिपेंडेंसी बताना, लेकिन बेज़ेल के टारगेट पैटर्न में एक से ज़्यादा टारगेट होते हैं. टारगेट पैटर्न, वाइल्डकार्ड का इस्तेमाल करके टारगेट के सेट के लिए, लेबल के सिंटैक्स की सामान्य जानकारी देते हैं. सबसे आसान मामले में, कोई भी मान्य लेबल मान्य टारगेट पैटर्न भी होता है, जो ठीक एक टारगेट के सेट की पहचान करता है.

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

//foo/bar:wiz सिर्फ़ एक टारगेट //foo/bar:wiz.
//foo/bar //foo/bar:bar के बराबर.
//foo/bar:all foo/bar पैकेज में सभी नियम टारगेट.
//foo/... सभी नियम, foo डायरेक्ट्री के नीचे मौजूद सभी पैकेज में टारगेट किए गए हैं.
//foo/...:all सभी नियम, foo डायरेक्ट्री के नीचे मौजूद सभी पैकेज में टारगेट किए गए हैं.
//foo/...:* डायरेक्ट्री foo के नीचे दिए गए सभी पैकेज में सभी टारगेट (नियम और फ़ाइलें) मौजूद हैं.
//foo/...:all-targets डायरेक्ट्री foo के नीचे दिए गए सभी पैकेज में सभी टारगेट (नियम और फ़ाइलें) मौजूद हैं.
//... फ़ाइल फ़ोल्डर में पैकेज के सभी टारगेट. इसमें बाहरी डेटा स्टोर करने की जगहों के टारगेट शामिल नहीं हैं.
//:all अगर फ़ाइल फ़ोल्डर के रूट पर `build` फ़ाइल है, तो टॉप-लेवल पैकेज में सभी टारगेट.

// से शुरू नहीं होने वाले टारगेट पैटर्न, मौजूदा काम कर रही डायरेक्ट्री के हिसाब से हल किए जाते हैं. ये उदाहरण, foo की किसी चालू डायरेक्ट्री की जानकारी देते हैं:

:foo //foo:foo के बराबर.
bar:wiz //foo/bar:wiz के बराबर.
bar/wiz इसके बराबर:
  • अगर foo/bar/wiz एक पैकेज है, तो //foo/bar/wiz:wiz
  • अगर foo/bar एक पैकेज है, तो //foo/bar:wiz
  • अन्य मामलों में //foo:bar/wiz
bar:all //foo/bar:all के बराबर.
:all //foo:all के बराबर.
...:all //foo/...:all के बराबर.
... //foo/...:all के बराबर.
bar/...:all //foo/bar/...:all के बराबर.

डिफ़ॉल्ट रूप से, डायरेक्ट्री सिमलिंक को बार-बार होने वाले टारगेट पैटर्न के लिए फ़ॉलो किया जाता है. हालांकि, ये उन आउटपुट एलिमेंट के अलावा नहीं होते जो आउटपुट के नीचे दिए गए हैं, जैसे कि फ़ाइल फ़ोल्डर की रूट डायरेक्ट्री में बनाए गए सुविधा वाले लिंक.

इसके अलावा, बेज़ेल किसी भी डायरेक्ट्री में बार-बार होने वाले टारगेट पैटर्न का आकलन करते समय, सिमलिंक का पालन नहीं करती है. इन डायरेक्ट्री में, नीचे दी गई फ़ाइल शामिल होती है: DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN

foo/...क्या यह वाइल्डकार्ड खत्म हैपैकेज, सभी पैकेज के बारे में बार-बार बताने वाली डायरेक्ट्री की जानकारी दी जाती हैfoo (पैकेज पाथ के सभी रूट के लिए). :all एक वाइल्डकार्ड टारगेट है जो किसी पैकेज में मौजूद सभी नियमों से मेल खाता है. foo/...:all की तरह ही इन दोनों को जोड़ा जा सकता है और जब दोनों वाइल्डकार्ड का इस्तेमाल किया जाता है, तो इन्हें foo/... से छोटा किया जा सकता है.

इसके अलावा, :* (या:all-targets ) एक वाइल्डकार्ड है जो इससे मेल खाता हैहर टारगेट मेल खाने वाले पैकेज में, इनमें वे फ़ाइलें भी शामिल होती हैं जिन्हें आम तौर पर कोई नियम नहीं बनाया जाता, जैसे_deploy.jar इससे जुड़ी फ़ाइलेंjava_binary नियम.

इसका मतलब है कि :*, :all के सुपरसेट के बारे में बताता है; हालांकि, यह कन्फ़र्मेशन संभावित रूप से सही है, लेकिन यह सिंटैक्स प्रचलित :all वाइल्डकार्ड को सामान्य बिल्ड के लिए इस्तेमाल करने की अनुमति देता है, जहां _deploy.jar जैसे बिल्डिंग टारगेट नहीं बनाए जाने चाहिए.

इसके अलावा, बैजल, लेबल सिंटैक्स के लिए ज़रूरी कोलन के बजाय, स्लैश का इस्तेमाल करने की अनुमति देता है; Bash फ़ाइल नाम विस्तार का इस्तेमाल करते समय यह अक्सर सुविधाजनक होता है. उदाहरण के लिए, foo/bar/wiz, //foo/bar:wiz (अगर कोई पैकेज foo/bar हो) या //foo:bar/wiz (अगर कोई पैकेज foo हो) के बराबर होता है.

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

bazel build foo/... bar/...

का मतलब है "foo के नीचे सभी टारगेट बनाना और bar के नीचे सभी टारगेट",

bazel build -- foo/... -foo/bar/...

का मतलब है "नीचे दिए गए सभी टारगेट बनाएंfoo इसे छोड़कर उससे कमfoo/bar". (-- इससे शुरू होने वाले तर्कों को रोकने के लिए तर्क की ज़रूरत होती है- को अतिरिक्त विकल्पों के रूप में समझा जा रहा हो.)

हालांकि, यह ध्यान देना ज़रूरी है कि इस तरह से टारगेट घटाने से इस बात की गारंटी नहीं मिलती है कि टारगेट को बनाया नहीं गया है, क्योंकि यह टारगेट पर निर्भर करता है. उदाहरण के लिए, अगर कोई //foo:all-apis टारगेट है जो //foo/bar:api पर निर्भर है, तो बाद वाला टारगेट पूर्व

इसके साथ टारगेटtags = ["manual"] वाइल्डकार्ड टारगेट पैटर्न में शामिल नहीं हैं (... ,:* ,:all , वगैरह) जैसे निर्देशों में बताए जाने पर bazel build औरbazel test ; अगर आप बेज़ेल को टेस्ट/टेस्ट बनाना चाहते हैं, तो आपको कमांड लाइन पर साफ़ तौर पर टारगेट किए गए पैटर्न वाले ऐसे टेस्ट टारगेट बताने होंगे. इसके उलट, bazel query ऐसी किसी भी तरह से अपने-आप फ़िल्टर नहीं करता है (जिसकी वजह से bazel query का इस्तेमाल नहीं हो पाएगा).

बाहरी डिपेंडेंसी फ़ेच की जा रही है

डिफ़ॉल्ट रूप से, बैजल बिल्ड के दौरान बाहरी डिपेंडेंसी डाउनलोड और सिमलिंक करेगा. हालांकि, यह ज़रूरी नहीं हो सकता, क्योंकि आप यह जानना चाहते हैं कि कब दूसरी बाहरी डिपेंडेंसी जोड़ी जा रही हैं या आप "प्रीफ़ेच" डिपेंडेंसी चाहते हैं (जैसे, किसी फ़्लाइट से पहले जहां आप ऑफ़लाइन होंगे) ). अगर आप बिल्ड के दौरान नई डिपेंडेंसी जोड़ने से रोकना चाहते हैं, तो आप --fetch=false फ़्लैग बता सकते हैं. ध्यान रखें कि यह फ़्लैग सिर्फ़ डेटा स्टोर करने की जगह के नियमों पर लागू होता है जो स्थानीय फ़ाइल सिस्टम की डायरेक्ट्री पर नहीं जाता. उदाहरण के लिए, local_repository, new_local_repository, और Android SDK टूल और NDK के डेटा स्टोर करने के नियम, हमेशा --fetch पर ध्यान दिए बिना लागू होंगे .

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

आप bazel fetch चलाकर मैन्युअल रूप से डिपेंडेंसी ला सकते हैं. अगर आप बिल्ड करते समय अनुमति नहीं देते हैं, तो आपको bazel fetch चलाना होगा:

  • पहली बार बनाने से पहले.
  • नई बाहरी निर्भरता जोड़ने के बाद.

एक बार इसे चलाने के बाद, आपको WORKSPACE फ़ाइल में बदलाव होने तक इसे फिर से चलाने की ज़रूरत नहीं होनी चाहिए.

fetch, डिपेंडेंसी फ़ेच करने के लिए, टारगेट की सूची लेता है. उदाहरण के लिए, यह //foo:bar और //bar:baz बनाने के लिए ज़रूरी डिपेंडेंसी फ़ेच करेगा:

bazel fetch //foo:bar //bar:baz

फ़ाइल फ़ोल्डर के लिए सभी बाहरी डिपेंडेंसी फ़ेच करने के लिए, चलाएं:

bazel fetch //...

अगर आपके पास अपने फ़ाइल फ़ोल्डर रूट के सभी टूल हैं, जिनका आप इस्तेमाल कर रहे हैं (लाइब्रेरी लाइब्रेरी से लेकर जेडीके तक) तो आपको बैजल फ़ेच की ज़रूरत नहीं है. हालांकि, अगर आप फ़ाइल फ़ोल्डर डायरेक्ट्री के बाहर कुछ भी इस्तेमाल कर रहे हैं, तो बैजेल अपने-आप bazel fetch के चलने से पहले चलेगा bazel build.

डेटा स्टोर करने की जगह का कैश मेमोरी

बज़ेल एक ही फ़ाइल को कई बार लाने से बचने की कोशिश करता है, भले ही अलग-अलग फ़ाइल फ़ोल्डर में एक ही फ़ाइल की ज़रूरत हो या किसी बाहरी डेटा स्टोर करने की जगह की परिभाषा बदल गई हो, लेकिन उसे अब भी डाउनलोड करने के लिए एक ही फ़ाइल की ज़रूरत हो. ऐसा करने के लिए, बेज़ेल रिपॉज़िटरी कैश मेमोरी में डाउनलोड की गई सभी फ़ाइलों को कैश मेमोरी में सेव कर लेता है. डिफ़ॉल्ट रूप से, यह फ़ाइल ~/.cache/bazel/_bazel_$USER/cache/repos/v1/ पर मौजूद होती है. --repository_cache विकल्प की मदद से जगह की जानकारी बदली जा सकती है. कैश मेमोरी को सभी फ़ाइल फ़ोल्डर और इंस्टॉल किए गए सभी वर्शन के बीच शेयर किया जाता है. अगर कैशल को पता है कि कैश फ़ाइल में सही फ़ाइल की कॉपी है, तो वह कैश मेमोरी में सेव की जाती है. इसका मतलब है कि अगर डाउनलोड अनुरोध में, बताई गई फ़ाइल का SHA256 योग है और फ़ाइल में {101) मौजूद है }हैश कैश मेमोरी में है. इसलिए हर एक बाहरी फ़ाइल के लिए एक हैश तय करना न सिर्फ़ सुरक्षा के नज़रिए से एक अच्छा आइडिया है; यह गैर-ज़रूरी डाउनलोड से बचने में भी मदद करता है.

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

वितरण फ़ाइलें निर्देशिका

वितरण डायरेक्ट्री, डाउनलोड होने से बचने के लिए एक और तरीका है. बेज़ेल, डेटा स्टोर करने की कैश मेमोरी से पहले, डायरेक्ट्री उपलब्ध कराना चाहता है. मुख्य अंतर यह है कि डिस्ट्रिब्यूशन डायरेक्ट्री में मैन्युअल तरीके से तैयारी करनी होती है.

--distdir=/path/to-directory विकल्प का इस्तेमाल करके, आप फ़ाइलों को ढूंढने के बजाय सिर्फ़ पढ़ने के लिए अतिरिक्त डायरेक्ट्री तय कर सकते हैं. अगर फ़ाइल का नाम यूआरएल के मूल नाम के बराबर है और फ़ाइल के हैश के बराबर डाउनलोड अनुरोध में बताया गया है, तो फ़ाइल ऐसी डायरेक्ट्री से ली जाती है. यह सिर्फ़ तब काम करता है, जब फ़ाइल हैश WORKSPACE के एलान में बताया गया हो.

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

तेज़ हवा वाले माहौल में बाज़ेल

बैजल के बाइनरी साइज़ को छोटा रखने के लिए, बेज़ेल की इंडिपेंडेंसी डिपेंडेंसी पहली बार नेटवर्क चलाते समय नेटवर्क से लाई जाती है. अलग-अलग तरह की डिपेंडेंसी, टूल टूल और नियमों के हिसाब से काम करती हैं. हो सकता है कि ये टूल सभी के लिए ज़रूरी न हों. उदाहरण के लिए, Android टूल बंडल किए जाते हैं और सिर्फ़ Android प्रोजेक्ट बनाते समय लाए जाते हैं.

हालांकि, इन इंडिपेंडेंसी डिपेंडेंसी के चलते, हवा के झंझटों की वजह से Belel चलाने पर समस्या हो सकती है. भले ही, आपने अपनी सभी 'Workspace डिपेंडेंसी' बेची हों. इसे हल करने के लिए, आप नेटवर्क पर पहुंच रखने वाली मशीन पर इन डिपेंडेंसी को शामिल करके एक डिस्ट्रिब्यूशन डायरेक्ट्री बना सकते हैं, और फिर उन्हें ऑफ़लाइन पहुंच के साथ एयरगैप किए गए परिवेश में ट्रांसफ़र कर सकते हैं.

डिस्ट्रिब्यूशन डायरेक्ट्री बनाने के लिए, --distdir फ़्लैग का इस्तेमाल करें. आपको हर नए Bazel बाइनरी वर्शन के लिए एक बार ऐसा करना होगा, क्योंकि हर रिलीज़ के लिए डिपेंडेंसी अलग हो सकती है.

अपने डिवाइस पर बिना रुकावट के काम करने की जगह के साथ-साथ, डिपेंडेंसी बनाने के लिए, पहले सही वर्शन पर बाज़ेल सोर्स ट्री देखें:

git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"
cd "$BAZEL_DIR"
git checkout "$BAZEL_VERSION"

फिर, उस खास Bazel वर्शन के लिए छिपे हुए रनटाइम डिपेंडेंसी के साथ टारबॉल बनाएं:

bazel build @additional_distfiles//:archives.tar

इस टारबॉल को उस डायरेक्ट्री में एक्सपोर्ट करें जिसे आपके एयरपैस में कॉपी किया जा सकता है. --strip-components फ़्लैग पर ध्यान दें, क्योंकि --distdir डायरेक्ट्री नेस्टिंग स्तर की मदद से अच्छे से काम कर सकता है:

tar xvf bazel-bin/external/additional_distfiles/archives.tar \
  -C "$NEW_DIRECTORY" --strip-components=3

आखिर में, जब आप अपने हवा के झंझटों में बैजल का इस्तेमाल करते हैं, तो डायरेक्ट्री की ओर ले जाने वाले --distdir फ़्लैग को पास करें. सुविधा के लिए, आप इसे .bazelrc प्रवेश के रूप में जोड़ सकते हैं:

build --distdir=path/to/directory

कॉन्फ़िगरेशन और क्रॉस-कंपाइलेशन बनाना

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

किसी दिए गए बिल्ड में, एक से ज़्यादा कॉन्फ़िगरेशन हो सकते हैं. क्रॉस-कंपाइल करने पर विचार करें. इसमें आप 64-बिट वाले आर्किटेक्चर के लिए //foo:bin एक्ज़ीक्यूटेबल बनाते हैं, लेकिन आपका वर्कस्टेशन 32-बिट मशीन है. साफ़ तौर पर, बिल्ड के लिए 64-बिट निष्पादन योग्य बनाने के टूल की मदद से //foo:bin बनाने की ज़रूरत होगी, लेकिन बिल्ड सिस्टम को बिल्ड के दौरान इस्तेमाल किए जाने वाले कई टूल भी बनाने होंगे—उदाहरण के लिए जो टूल स्रोत से बनाई गई हैं, फिर बाद में इस्तेमाल किया जाता है, जैसे कि नियम. ये आपके वर्कस्टेशन पर बनाए जाने के लिए बनाए जाने चाहिए. इस तरह, हम दो कॉन्फ़िगरेशन की पहचान कर सकते हैं: होस्ट कॉन्फ़िगरेशन, जिसका इस्तेमाल बिल्ड के दौरान चलने वाले टूल बनाने के लिए किया जाता है और टारगेट कॉन्फ़िगरेशन (या कॉन्फ़िगरेशन का अनुरोध करें, लेकिन हम "टारगेट कॉन्फ़िगरेशन" को ज़्यादा बार कहते हैं, हालांकि उस शब्द का कई मतलब होता है) .

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

बैजल, --distinct_host_configuration विकल्प के आधार पर, होस्ट कॉन्फ़िगरेशन को चुनने के लिए दो तरीकों में से एक का इस्तेमाल करता है. यह बूलियन विकल्प कुछ हद तक हल्का है, और सेटिंग से आपके बिल्ड की गति बेहतर हो सकती है (या खराब हो सकती है).

--distinct_host_configuration=false

यह विकल्प गलत होने पर, होस्ट और अनुरोध के कॉन्फ़िगरेशन एक जैसे होते हैं: बिल्ड के दौरान ज़रूरी सभी टूल ठीक उसी तरह बनाए जाएंगे जिस तरह टारगेट प्रोग्राम बनाए जाते हैं. इस सेटिंग का मतलब है कि एक बिल्ड के दौरान दो बार लाइब्रेरी बनाने की ज़रूरत नहीं होती.

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

--distinct_host_configuration=true (डिफ़ॉल्ट)

अगर यह विकल्प सही है, तो होस्ट और अनुरोध के लिए एक ही कॉन्फ़िगरेशन का इस्तेमाल करने के बजाय, एक पूरी तरह से अलग होस्ट कॉन्फ़िगरेशन का इस्तेमाल किया जाता है. होस्ट कॉन्फ़िगरेशन को टारगेट कॉन्फ़िगरेशन से इस तरह हासिल किया जाता है:

  • जब तक --host_crosstool_top बताया न गया हो, तब तक अनुरोध कॉन्फ़िगरेशन में बताए गए क्रॉसटूल (--crosstool_top) के उसी वर्शन का इस्तेमाल करें.
  • --cpu के लिए --host_cpu मान का उपयोग करें (डिफ़ॉल्ट: k8).
  • इन विकल्पों के लिए उसी मान का इस्तेमाल करें, जो अनुरोध कॉन्फ़िगरेशन में बताया गया है: --compiler, --use_ijars, और अगर --host_crosstool_top का इस्तेमाल किया जाता है, तो --host_cpu के मान का इस्तेमाल किया जाता है क्रॉस-टूल (--compiler पर ध्यान न देते हुए) होस्ट कॉन्फ़िगरेशन के लिए एक default_toolchain देखें.
  • --javabase के लिए --host_javabase के मान का उपयोग करें
  • --java_toolchain के लिए --host_java_toolchain के मान का उपयोग करें
  • C++ कोड (-c opt) के लिए, ऑप्टिमाइज़ किए गए बिल्ड का इस्तेमाल करें.
  • डीबग करने की कोई जानकारी जनरेट न करें (--copt=-g0).
  • एक्ज़ीक्यूटेबल और शेयर की गई लाइब्रेरी से डीबग की जानकारी हटाएं (--strip=always).
  • सभी मिलने वाली फ़ाइलों को ऐसे विशेष स्थान पर रखें, जो किसी भी संभावित अनुरोध कॉन्फ़िगरेशन में इस्तेमाल किए गए स्थान से अलग हो.
  • बिल्ड डेटा से बाइनरी के लिए स्टैंप इकट्ठा करें (--embed_* विकल्प देखें).
  • बाकी सभी मान अपने डिफ़ॉल्ट पर बने रहते हैं.

ऐसे कई कारण हो सकते हैं कि अनुरोध कॉन्फ़िगरेशन से एक अलग होस्ट कॉन्फ़िगरेशन चुनना पसंद किया जाए. यहां कुछ चीज़ों का ज़िक्र करना बहुत अच्छा लगता है, लेकिन उनमें से दो का मतलब यह है कि वे समस्या को ठीक करने की कोशिश करते हैं.

सबसे पहले, धारीदार, ऑप्टिमाइज़ की गई बाइनरी का इस्तेमाल करके, आप टूल को लिंक करने और एक्ज़ीक्यूट करने में लगने वाला समय कम करते हैं. इसके लिए, टूल के पास मौजूद डिस्क की जगह और डिस्ट्रिब्यूटेड बिल्ड में नेटवर्क I/O का समय कम होता है.

दूसरी बात यह है कि सभी बिल्ड में होस्ट और अनुरोध कॉन्फ़िगरेशन को अलग करके, आप फिर से बनाए गए बहुत महंगे विज्ञापनों से बच जाते हैं. ये अनुरोध अनुरोध के कॉन्फ़िगरेशन में मामूली बदलाव करने (जैसे कि लिंक करने वाले विकल्प में बदलाव करना) से होते हैं. जैसा कि पहले बताया गया है चुनें.

हालांकि, कुछ बिल्ड के लिए यह विकल्प एक विकल्प हो सकता है. खास तौर पर, ऐसा कॉन्फ़िगरेशन बनाता है जिसमें कॉन्फ़िगरेशन कभी-कभी ही (खास तौर पर कुछ Java बिल्ड) होते हैं और यह वह जगह बनाता है जहां होस्ट और टारगेट कॉन्फ़िगरेशन, दोनों में कोड की बड़ी मात्रा होनी चाहिए, फ़ायदा नहीं होता चुनें.

इंक्रीमेंटल (बढ़ने वाले) सही तरीके से फिर से बनाना

बेज़ेल प्रोजेक्ट का मुख्य लक्ष्य यह पक्का करना है कि इंक्रीमेंटल (बढ़ने वाले) तरीके को सही तरीके से बढ़ाया जाए. पिछले बिल्ड टूल, खास तौर पर 'बनाएं' पर आधारित टूल, इंक्रीमेंटल बिल्ड लागू करने के बारे में कई बार गलत अनुमान लगाते हैं.

सबसे पहले, फ़ाइलों के टाइमस्टैंप लगातार एक जैसे दिखते हैं. हालांकि, यह सचमुच की बात है, लेकिन इस अंदाज़ा को समझना बहुत आसान है; किसी फ़ाइल के शुरुआती बदलाव में सिंक करने से फ़ाइल में बदलाव का समय कम हो जाता है; आधारित आधारित सिस्टम फिर से नहीं बनेंगे.

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

साथ ही, किसी सब-प्रोसेस के अपनी आउटपुट फ़ाइल में लिखना शुरू करने के बाद, 'बनाएं' सुविधा इसके किसी सब-प्रोसेस को खत्म नहीं किया जा सकता. अब बनाएं का मौजूदा एक्ज़ीक्यूशन काम नहीं करेगा, फिर भी 'बनाएं' को शुरू करने पर यह माना जाएगा कि छोटी की गई आउटपुट फ़ाइल मान्य है (क्योंकि यह इसके इनपुट से नई है). साथ ही, इसे फिर से नहीं बनाया जाएगा. इसी तरह, अगर 'बनाएं' प्रोसेस को बंद कर दिया जाता है, तो ऐसी ही स्थिति हो सकती है.

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

इंक्रीमेंटल (बढ़ने वाले) बिल्ड वाले उपयोगकर्ताओं को यह फ़ायदा मिलता है: भ्रम की स्थिति की वजह से कम समय खर्च करना. (साथ ही, make clean के इस्तेमाल की वजह से फिर से बनाने पर ज़्यादा समय न बिताया गया हो. ज़रूरत पड़ने पर या पहले से काम करने पर भी ऐसा होता है.)

एक जैसा और लगातार बढ़ने वाला बिल्ड बनाना

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

एक दूसरे तरह का असंगतता है जो बहुत ही ज़्यादा परेशानी पैदा करती है: स्थिरता एक जैसी होनी चाहिए. अगर बिल्ड, स्थिर असंगत स्थिति में पहुंच जाता है, तो बिल्ड टूल को बार-बार लागू करने से अनुकूलता बहाल नहीं होती है: बिल्ड "स्टक" हो गया है और आउटपुट गलत बने रहेंगे. एक जैसा अनुभव न देने वाली स्थितियां, उपयोगकर्ताओं को make clean बनाने (और दूसरे बिल्ड टूल) के टाइप करने की मुख्य वजह होती हैं. यह पता लगाना कि बिल्ड टूल इस तरह से काम नहीं कर पाया (और उसके बाद उसे वापस पाना) बहुत समय लेने वाला और बहुत परेशान करने वाला हो सकता है.

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

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

जैसा कि सभी गारंटी के साथ होता है, कुछ छोटे-मोटे प्रिंट भी होते हैं: बैजल के साथ स्थिर असंगत स्थिति में जाने के कुछ ज्ञात तरीके हैं. हम इंक्रीमेंटल डिपेंडेंसी के विश्लेषण में बग की पहचान करने की कोशिशों की वजह से होने वाली ऐसी समस्याओं की जांच करने की गारंटी नहीं देंगे. हालांकि, हम आम तौर पर होने वाली या बिल्ड टूल का सही उपयोग.

अगर आपको कभी भी बैजेल के साथ एक स्थिर असंगत स्थिति का पता चलता है, तो कृपया किसी बग की रिपोर्ट करें.

सैंडबॉक्स किया गया एक्ज़ीक्यूशन

बैजल इस बात की पुष्टि करने के लिए सैंडबॉक्स का इस्तेमाल करता है कि कार्रवाइयां सही तरीके से और सही तरीके से चल रही हैं. बेज़ेल रनस्पून (धीमे महसूस करने वाली: कार्रवाइयां) सैंडबॉक्स में सिर्फ़ ऐसी फ़ाइलों का कम से कम सेट शामिल होता है जो टूल को अपना काम करने के लिए ज़रूरी होती हैं. फ़िलहाल, सैंडबॉक्सिंग Linux 3.12 या उसके बाद के वर्शन पर काम करती है, जबकि CONFIG_USER_NS विकल्प चालू है और macOS 10.11 या उसके बाद के वर्शन पर भी काम करती है.

अगर सिस्टम इस चेतावनी को बंद करने के लिए, आप बैजल को --ignore_unsupported_sandboxing के लिए फ़्लैग कर सकते हैं.

Google Kubernetes Engine क्लस्टर के नोड या Debian, जैसे कुछ प्लैटफ़ॉर्म पर, सुरक्षा से जुड़ी समस्याओं की वजह से उपयोगकर्ता के नेमस्पेस डिफ़ॉल्ट तौर पर बंद हो जाते हैं. फ़ाइल को देखकर इसकी जांच की जा सकती है /proc/sys/kernel/unprivileged_userns_clone: अगर यह मौजूद है और इसमें 0 है, तो उपयोगकर्ता नाम स्थान sudo sysctl kernel.unprivileged_userns_clone=1 के साथ चालू किए जा सकते हैं.

कुछ मामलों में, सिस्टम सेट अप की वजह से Bazel सैंडबॉक्स, नियमों को लागू नहीं कर पाता है. आम तौर पर, यह समस्या namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory में होने वाले मैसेज को आउटपुट नहीं कर पाने की वजह से होती है. इस मामले में, सैंडबॉक्स के लिए सैंडबॉक्स को --strategy=Genrule=standalone के साथ और --spawn_strategy=standalone वाले दूसरे नियमों को बंद करने की कोशिश करें. साथ ही, हमारे समस्या ट्रैकर पर गड़बड़ी की रिपोर्ट करें. साथ ही, बताएं कि आप कौनसा Linux डिस्ट्रीब्यूशन इस्तेमाल कर रहे हैं. इससे, हम उसकी जांच कर सकेंगे और आने वाले रिलीज़ में समस्या को ठीक कर सकेंगे.

बिल्ड के चरण

बैजल में एक बिल्ड तीन अलग-अलग चरणों में होता है; एक उपयोगकर्ता के तौर पर, इन दोनों के बीच के अंतर को समझने से उन विकल्पों की अहम जानकारी मिलती है जिनसे बिल्ड नियंत्रित होता है (नीचे देखें).

फ़ेज़ लोड हो रहा है

पहली लोडिंग होती है, जिसके दौरान शुरुआती टारगेट के लिए सभी ज़रूरी बिल्ड फ़ाइलें और दूसरी तरह की डिपेंडेंसी पूरी तरह से लोड हो जाती हैं, पार्स हो जाती हैं, जांच की जाती हैं, और कैश की जाती हैं.

बैज इसके बाद के बिल्ड, खास तौर पर अगर कोई बिल्ड फ़ाइल नहीं बदली गई है, तो लोड होना बहुत जल्दी हो जाता है.

इस चरण के दौरान रिपोर्ट की गई गड़बड़ियों में ये शामिल हैं: पैकेज नहीं मिला, टारगेट नहीं मिला, बिल्ड फ़ाइल में शाब्दिक और व्याकरण की गड़बड़ियां, और मूल्यांकन की गड़बड़ियां.

विश्लेषण का चरण

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

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

इस चरण में रिपोर्ट की गई गड़बड़ियों में ये शामिल हैं: गलत डिपेंडेंसी, नियम के लिए अमान्य इनपुट, और सभी नियम-खास गड़बड़ी के मैसेज.

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

बदलाव लागू करने का चरण

बिल्ड का तीसरा और आखिरी चरण एक्ज़ीक्यूशन है. यह चरण पक्का करता है कि बिल्ड के हर चरण के आउटपुट, इसके इनपुट, कंपाइलेशन/लिंकिंग/वगैरह वगैरह के मुताबिक हों. ज़रूरत के मुताबिक टूल. यह तरीका वह जगह है जहां बिल्ड का ज़्यादातर समय एक सेकंड से लेकर एक बड़े बिल्ड के लिए एक घंटे तक लगता है. इस चरण में रिपोर्ट की गई गड़बड़ियों में ये शामिल हैं: अनुपलब्ध स्रोत फ़ाइलें, कुछ बिल्ड कार्रवाई के ज़रिए निष्पादित टूल में गड़बड़ियां या आउटपुट के अपेक्षित सेट बनाने में किसी टूल की नाकामी.