आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम

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

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

फ़ंक्शनल नज़रिए से

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

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

आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम के बारे में समझना

Google का बिल्ड सिस्टम, Blaze, आर्टफ़ैक्ट पर आधारित पहला बिल्ड सिस्टम था. Bazel, Blaze का ओपन-सोर्स वर्शन है.

Bazel में बिल्डफ़ाइल (आम तौर पर, इसका नाम BUILD होता है) कुछ इस तरह दिखती है:

java_binary(
    name = "MyBinary",
    srcs = ["MyBinary.java"],
    deps = [
        ":mylib",
    ],
)
java_library(
    name = "mylib",
    srcs = ["MyLibrary.java", "MyHelper.java"],
    visibility = ["//java/com/example/myproduct:__subpackages__"],
    deps = [
        "//java/com/example/common",
        "//java/com/example/myproduct/otherlib",
    ],
)

Bazel में, BUILD फ़ाइलें टारगेट तय करती हैं. यहां दो तरह के टारगेट दिए गए हैं: java_binary और java_library. हर टारगेट, एक आर्टफ़ैक्ट से जुड़ा होता है, जिसे सिस्टम बना सकता है. बाइनरी टारगेट, ऐसी बाइनरी जनरेट करते हैं जिन्हें सीधे तौर पर चलाया जा सकता है. वहीं, लाइब्रेरी टारगेट, ऐसी लाइब्रेरी जनरेट करते हैं जिनका इस्तेमाल बाइनरी या अन्य लाइब्रेरी कर सकती हैं. हर टारगेट में ये चीज़ें होती हैं:

  • name: कमांड लाइन और अन्य टारगेट पर, टारगेट को कैसे रेफ़र किया जाता है
  • srcs: टारगेट के लिए आर्टफ़ैक्ट बनाने के लिए, कंपाइल की जाने वाली सोर्स फ़ाइलें
  • deps: अन्य टारगेट जिन्हें इस टारगेट से पहले बिल्ड किया जाना चाहिए और इससे लिंक किया जाना चाहिए

डिपेंडेंसी, एक ही पैकेज में हो सकती हैं. जैसे, MyBinary की डिपेंडेंसी :mylib पर. इसके अलावा, ये एक ही सोर्स के क्रम में मौजूद किसी दूसरे पैकेज में भी हो सकती हैं . जैसे, mylib की डिपेंडेंसी //java/com/example/common पर.

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

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

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

हालांकि, इसके फ़ायदे सिर्फ़ पैरललिज़्म तक सीमित नहीं हैं. इस अप्रोच का अगला फ़ायदा तब दिखता है, जब डेवलपर बिना कोई बदलाव किए दूसरी बार bazel build :MyBinary टाइप करता है. Bazel, एक सेकंड से भी कम समय में यह मैसेज दिखाकर बंद हो जाता है कि टारगेट अप-टू-डेट है. यह, फ़ंक्शनल प्रोग्रामिंग के उस पैराडाइम की वजह से मुमकिन है जिसके बारे में हमने पहले बात की थी. Bazel को पता है कि हर टारगेट, सिर्फ़ Java कंपाइलर चलाने का नतीजा है. साथ ही, उसे पता है कि Java कंपाइलर का आउटपुट सिर्फ़ उसके इनपुट पर निर्भर करता है. इसलिए, जब तक इनपुट में कोई बदलाव नहीं होता, तब तक आउटपुट को दोबारा इस्तेमाल किया जा सकता है. यह विश्लेषण हर लेवल पर काम करता है. अगर MyBinary.java में बदलाव होता है, तो Bazel को पता होता है कि MyBinary को दोबारा बिल्ड करना है, लेकिन mylib को दोबारा इस्तेमाल किया जा सकता है. अगर //java/com/example/common के लिए सोर्स फ़ाइल में बदलाव होता है, तो Bazel को पता होता है कि उस लाइब्रेरी, mylib, और MyBinary को दोबारा बिल्ड करना है. हालांकि, //java/com/example/myproduct/otherlib को दोबारा इस्तेमाल किया जा सकता है. Bazel को हर चरण में चलाए जाने वाले टूल की प्रॉपर्टी के बारे में पता होता है. इसलिए, यह हर बार सिर्फ़ आर्टफ़ैक्ट के ज़रूरी सेट को दोबारा बिल्ड कर पाता है. साथ ही, यह गारंटी देता है कि यह पुराने बिल्ड जनरेट नहीं करेगा.

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

Bazel की अन्य शानदार सुविधाएं

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

टूल को डिपेंडेंसी के तौर पर इस्तेमाल करना

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

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

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

  • होस्ट कॉन्फ़िगरेशन: बिल्ड के दौरान चलने वाले टूल को बिल्ड करना
  • टारगेट कॉन्फ़िगरेशन: वह बाइनरी बिल्ड करना जिसका आपने अनुरोध किया था

बिल्ड सिस्टम को बढ़ाना

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

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

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

एनवायरमेंट को अलग करना

ऐसा लग सकता है कि कार्रवाइयों को अन्य सिस्टम में मौजूद टास्क की तरह ही समस्याएं आ सकती हैं. क्या ऐसी कार्रवाइयां लिखना अब भी मुमकिन नहीं है जो एक ही फ़ाइल में लिखती हैं और एक-दूसरे से टकराती हैं? दरअसल, Bazel, सैंडबॉक्सिंग का इस्तेमाल करके, इन टकरावों को रोक सकता है. सपोर्ट किए गए सिस्टम पर, हर कार्रवाई को फ़ाइल सिस्टम सैंडबॉक्स के ज़रिए, अन्य कार्रवाइयों से अलग किया जाता है. असल में, हर कार्रवाई, फ़ाइल सिस्टम का सिर्फ़ सीमित व्यू देख सकती है. इसमें, तय किए गए इनपुट और जनरेट किए गए आउटपुट शामिल होते हैं. इसे Linux पर LXC जैसे सिस्टम लागू करते हैं. यह वही टेक्नोलॉजी है जो Docker में इस्तेमाल की जाती है. इसका मतलब है कि कार्रवाइयों के बीच टकराव नहीं हो सकता, क्योंकि वे उन फ़ाइलों को नहीं पढ़ सकतीं जिन्हें उन्होंने तय नहीं किया है. साथ ही, वे जिन फ़ाइलों को लिखती हैं, लेकिन तय नहीं करतीं वे कार्रवाई पूरी होने पर हटा दी जाती हैं. Bazel, कार्रवाइयों को नेटवर्क के ज़रिए कम्यूनिकेट करने से रोकने के लिए भी सैंडबॉक्स का इस्तेमाल करता है.

बाहरी डिपेंडेंसी को डिटरमिनिस्टिक बनाना

अब भी एक समस्या बाकी है. बिल्ड सिस्टम को अक्सर डिपेंडेंसी (टूल या लाइब्रेरी) को सीधे तौर पर बिल्ड करने के बजाय, बाहरी सोर्स से डाउनलोड करना पड़ता है. इसे उदाहरण में @com_google_common_guava_guava//jar डिपेंडेंसी के ज़रिए देखा जा सकता है. यह Maven से JAR फ़ाइल डाउनलोड करती है.

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

असल समस्या यह है कि हम चाहते हैं कि बिल्ड सिस्टम को इन फ़ाइलों के बारे में पता हो. इसके लिए, हमें उन्हें सोर्स कंट्रोल में शामिल करने की ज़रूरत नहीं है. डिपेंडेंसी को अपडेट करना एक सोच-समझकर लिया गया फ़ैसला होना चाहिए. हालांकि, यह फ़ैसला किसी एक जगह पर लिया जाना चाहिए. इसे अलग-अलग इंजीनियरों या सिस्टम की ओर से अपने-आप मैनेज नहीं किया जाना चाहिए. ऐसा इसलिए, क्योंकि “लाइव ऐट हेड” मॉडल के साथ भी, हम चाहते हैं कि बिल्ड डिटरमिनिस्टिक हों. इसका मतलब है कि अगर आपने पिछले हफ़्ते का कोई कमिट चेक आउट किया है, तो आपको अपनी डिपेंडेंसी वैसे ही दिखनी चाहिए जैसी वे तब थीं, न कि जैसी वे अब हैं.

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

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

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