Bazel से प्रोग्राम बनाएं

संग्रह की मदद से व्यवस्थित रहें अपनी प्राथमिकताओं के आधार पर, कॉन्टेंट को सेव करें और कैटगरी में बांटें.
समस्या की शिकायत करें स्रोत देखें

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

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

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

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

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

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

सहायता पाना

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

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

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

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

Bazel का इस्तेमाल करके कोई प्रोग्राम बनाने के लिए, 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 फ़ाइलों में ऐसी फ़ाइलें शामिल होती हैं. सभी डिपेंडेंसी की पहचान करने के बाद, Bazel ने उनका विश्लेषण किया और उन्हें बिल्ड ऐक्शन बनाया. आखिर में, Bazel कंपाइलर और अन्य टूल बनाता है.

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

बिल्ड के आखिर में, बेज़ल ने उन टारगेट प्रिंट का अनुरोध किया था जिन्हें टारगेट किया गया था, चाहे वे सफलतापूर्वक बनाए गए हों या नहीं. अगर हां, तो आउटपुट फ़ाइलें कहां मिल सकती हैं. बिल्ड चलाने वाली स्क्रिप्ट, इस आउटपुट को सही तरीके से पार्स कर सकती हैं. ज़्यादा जानकारी के लिए --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 फ़ाइलों में डिपेंडेंसी का एलान करना, Bazel के टारगेट पैटर्न में एक से ज़्यादा टारगेट तय किए जाते हैं. टारगेट पैटर्न, वाइल्डकार्ड का इस्तेमाल करके टारगेट के सेट के लिए लेबल सिंटैक्स का एक सामान्य हिस्सा हैं. सबसे आसान मामले में, किसी भी मान्य लेबल को, एक मान्य टारगेट पैटर्न भी माना जाता है. इससे, सिर्फ़ एक टारगेट के सेट की पहचान की जाती है.

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

//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 अगर फ़ाइल फ़ोल्डर के रूट में `बिल्ड` फ़ाइल है, तो टॉप-लेवल पैकेज में मौजूद सभी टारगेट.

// से शुरू न होने वाले टारगेट पैटर्न, मौजूदा काम करने वाली डायरेक्ट्री के हिसाब से हल किए जाते हैं. ये उदाहरण, 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 की तरह ही काम करता है.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

bazel fetch //...

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

रिपॉज़िटरी कैश

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

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

डिस्ट्रिब्यूशन फ़ाइलें डायरेक्ट्री

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

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

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

हवा में अंतर वाली जगह पर बेज़ल चलाना

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

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

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

इन डिपेंडेंसी को अपने एयरलैप्स के बाहर बनाने के लिए, सबसे पहले बेज़ेल सोर्स ट्री को सही वर्शन में चेकआउट करें:

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

आखिर में, जब आप अपने हवादार जगह में Bazel का इस्तेमाल करते हैं, तो डायरेक्ट्री की ओर इशारा करने वाला --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 ढूंढने के लिए --host_cpu की वैल्यू का इस्तेमाल किया जाता है.
  • --javabase के लिए --host_javabase की वैल्यू का इस्तेमाल करें
  • --java_toolchain के लिए --host_java_toolchain की वैल्यू का इस्तेमाल करें
  • C++ कोड (-c opt) के लिए, ऑप्टिमाइज़ किए गए बिल्ड इस्तेमाल करें.
  • डीबग करने की कोई भी जानकारी जनरेट न करें (--copt=-g0).
  • एक्ज़ीक्यूटेबल और शेयर की गई लाइब्रेरी से डीबग जानकारी हटाएं (--strip=always).
  • सभी मिली हुई फ़ाइलों को किसी खास जगह पर रखें, ताकि उनका अनुरोध किया जा सके.
  • बिल्ड डेटा के साथ बाइनरी की स्टैंपिंग रोकें (--embed_* विकल्प देखें).
  • अन्य सभी वैल्यू अपनी डिफ़ॉल्ट वैल्यू पर ही रहती हैं.

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

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

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

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

इंक्रीमेंटल (फिर इंक्रीमेंटल) दोबारा बनाना

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

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

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

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

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

सही इंक्रीमेंटल बिल्ड के उपयोगकर्ताओं के लिए यह फ़ायदा है: भ्रम की वजह से समय की बर्बादी कम होती है. इसके अलावा, make clean का इस्तेमाल करने पर दोबारा बिल बनने में लगने वाला समय भी कम होता है, भले ही यह ज़रूरी हो या पहले से कुछ समय के लिए किया गया हो.)

लगातार और लगातार बढ़ने वाले बिल्ड बनाएं

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

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

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

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

जैसा कि सभी गारंटी के साथ, कुछ फ़ाइन प्रिंट भी होते हैं: Bazel से एक जैसी स्थिर स्थिति पाने के कुछ जाने-पहचाने तरीके हैं. हम इस बात की गारंटी नहीं देते कि बढ़ाने लायक डिपेंडेंसी में गड़बड़ियों का पता लगाने के लिए, जान-बूझकर ऐसी समस्याओं का पता लगाया जाएगा. हालांकि, हम बिल्ड टूल के सामान्य या "सही" इस्तेमाल की वजह से होने वाली सभी स्थिर स्थितियों को ठीक करने की पूरी कोशिश करेंगे.

अगर आपको कभी भी बेज़ल की स्थिति में कोई अंतर मिला है, तो कृपया गड़बड़ी की शिकायत करें.

सैंडबॉक्स लागू किया गया

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

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

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 का कौनसा वर्शन इस्तेमाल कर रहे हैं, ताकि हम उस समस्या की जांच कर सकें और उसे आने वाली रिलीज़ में ठीक कर सकें.

बिल्ड के चरण

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

लोडिंग फ़ेज़

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

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

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

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

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

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

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

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

एक्ज़ीक्यूशन का फ़ेज़

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