अगर A
को बिल्ड या एक्ज़ीक्यूट होने के समय B
की ज़रूरत हो, तो A
, टारगेट B
पर निर्भर करता है. यह संबंध इस पर निर्भर करता है कि टारगेट के ऊपर, डायरेक्ट असाइकलिक ग्राफ़
(डीएजी) बनता है. इसे डिपेंडेंसी ग्राफ़ कहा जाता है.
टारगेट की डायरेक्ट डिपेंडेंसी, वे अन्य टारगेट होती हैं जिन पर डिपेंडेंसी ग्राफ़ में लंबाई 1 के पाथ से पहुंचा जा सकता है. टारगेट की ट्रांज़िशन डिपेंडेंसी, वे टारगेट होती हैं जिन पर यह ग्राफ़ के ज़रिए, किसी भी लंबाई वाले पाथ से निर्भर करता है.
असल में, बिल्ड के संदर्भ में दो डिपेंडेंसी ग्राफ़ होते हैं. पहला, असल डिपेंडेंसी का ग्राफ़ और दूसरा, तय की गई डिपेंडेंसी का ग्राफ़. ज़्यादातर मामलों में, दोनों ग्राफ़ इतने मिलते-जुलते हैं कि इस फ़र्क़ को दिखाने की ज़रूरत नहीं है. हालांकि, यहां दी गई चर्चा के लिए इससे काम का है.
असल और तय की गई डिपेंडेंसी
अगर X
को सही तरीके से बनाने के लिए Y
मौजूद होना चाहिए, बनाया हुआ और अप-टू-डेट होना चाहिए, तो X
टारगेट Y
पर असल में निर्भर होता है. पहले से मौजूद का मतलब है, जनरेट किए गए, प्रोसेस किए गए, इकट्ठा किए गए, लिंक किए गए, संग्रहित किए गए, कंप्रेस किए गए, प्रोसेस किए गए या किसी दूसरे तरह के ऐसे टास्क जो बिल्ड के दौरान नियमित रूप से किए जाते हैं.
अगर X
के पैकेज में X
से Y
पर डिपेंडेंसी एज है, तो टारगेट X
में, टारगेट Y
पर डिपेंडेंसी होती है.
सही बिल्ड के लिए, असल डिपेंडेंसी का ग्राफ़ A, एलान की गई डिपेंडेंसी D के ग्राफ़ का सबग्राफ़ होना चाहिए. इसका मतलब है कि A में सीधे तौर पर जुड़े नोड x --> y
के हर जोड़े को भी D में सीधे तौर पर कनेक्ट किया जाना चाहिए. यह कहा जा सकता है कि D, A का ज़्यादा अनुमान है.
BUILD
फ़ाइल राइटर को बिल्ड सिस्टम पर लागू होने वाले हर नियम के लिए, सीधे तौर पर लागू होने वाली सभी असल डिपेंडेंसी के बारे में साफ़ तौर पर एलान करना चाहिए. इसके अलावा, इससे ज़्यादा जानकारी नहीं देनी होगी.
इस सिद्धांत को न देख पाने की वजह से काम नहीं करता: बिल्ड काम करना बंद कर सकता है, लेकिन इससे भी बुरा यह हो सकता है कि बिल्ड पहले किए गए कुछ कामों पर निर्भर हो या फिर, तय किए गए समय के बाद टारगेट की गई कुछ चीज़ों पर निर्भर हो. Bazel, छूटी हुई डिपेंडेंसी की जांच करता है और गड़बड़ियों की रिपोर्ट करता है. हालांकि, सभी मामलों में यह जांच पूरी नहीं हो सकती.
अप्रत्यक्ष रूप से इंपोर्ट की गई हर चीज़ की सूची बनाने की ज़रूरत नहीं है (और नहीं भी).
भले ही, लागू करने के समय A
तक इसकी ज़रूरत क्यों न हो.
टारगेट X
के बिल्ड के दौरान, बिल्ड टूल X
की डिपेंडेंसी के पूरी तरह बंद होने की पूरी प्रक्रिया की जांच करता है, ताकि यह पक्का किया जा सके कि उन टारगेट में किया गया कोई भी बदलाव फ़ाइनल नतीजे में दिखाया गया है या नहीं. साथ ही, ज़रूरत के मुताबिक इंटरमीडिएट को फिर से तैयार किया जाता है.
डिपेंडेंसी के ट्रांज़िटिव टाइप की वजह से एक आम गलती होती है. कभी-कभी,
एक फ़ाइल में मौजूद कोड में इनडायरेक्ट डिपेंडेंसी से मिले कोड का इस्तेमाल हो सकता है. यह डिपेंडेंसी के एलान किए गए ग्राफ़ में, ट्रांज़िशनिव होता है, लेकिन डायरेक्ट एज नहीं होता. BUILD
फ़ाइल में
इंडायरेक्ट डिपेंडेंसी नहीं दिखती. यह नियम सीधे तौर पर
सेवा देने वाली कंपनी पर निर्भर नहीं करता है. इसलिए, बदलावों को ट्रैक करने का कोई तरीका नहीं है, जैसा कि नीचे दी गई टाइमलाइन में
दिया गया है:
1. तय की गई डिपेंडेंसी, असल डिपेंडेंसी से मेल खाती हैं
सबसे पहले, सब कुछ काम करता है. a
पैकेज में मौजूद कोड, b
पैकेज में मौजूद कोड का इस्तेमाल करता है.
पैकेज b
का कोड, c
पैकेज में मौजूद कोड का इस्तेमाल करता है. इसलिए, a
, c
पर निर्भर करता है.
a/BUILD |
b/BUILD |
---|---|
rule( name = "a", srcs = "a.in", deps = "//b:b", ) |
rule( name = "b", srcs = "b.in", deps = "//c:c", ) |
a / a.in |
b / b.in |
import b; b.foo(); |
import c; function foo() { c.bar(); } |
तय की गई डिपेंडेंसी, असल डिपेंडेंसी के ज़्यादा करीब होती हैं. सब ठीक है.
2. अघोषित डिपेंडेंसी जोड़ना
जब कोई व्यक्ति a
में कोड जोड़ता है, तो यह तब होता है, जब कोई व्यक्ति c
पर असल डिपेंडेंसी बना लेता है, लेकिन बिल्ड फ़ाइल में इस बारे में जानकारी नहीं देता.a/BUILD
.
a / a.in |
|
---|---|
import b; import c; b.foo(); c.garply(); |
|
तय की गई डिपेंडेंसी, अब असल डिपेंडेंसी के अनुमान से ज़्यादा नहीं होती हैं.
इससे 'ठीक है' हो सकता है, क्योंकि दो ग्राफ़ के ट्रांज़िटिव बंद होने का अंतर बराबर होता है,
लेकिन समस्या को छिपा देता है: a
की c
पर असल में डिपेंडेंसी है, लेकिन यह तय नहीं है.
3. एलान किए गए और असल डिपेंडेंसी ग्राफ़ के बीच अंतर
यह खतरा तब पैदा होता है, जब कोई व्यक्ति b
को रीफ़ैक्टर करता है, ताकि उस पर निर्भर न रहें.
c
की वजह से अनजाने में a
हो गया है,
जिससे अपनी कोई गलती नहीं हुई है.
b/BUILD |
|
---|---|
rule( name = "b", srcs = "b.in", deps = "//d:d", ) |
|
b / b.in |
|
import d; function foo() { d.baz(); } |
|
एलान किया गया डिपेंडेंसी ग्राफ़, अब वास्तविक डिपेंडेंसी का कम अनुमान होता है. भले ही, यह ट्रांज़िशन के लिए बंद हो. इस दौरान, बिल्ड के काम न करने की संभावना भी हो सकती है.
यह पक्का करके समस्या को दूर किया जा सकता था कि दूसरे चरण में, a
से c
तक की गई डिपेंडेंसी के बारे में BUILD
फ़ाइल में सही जानकारी दी गई थी.
डिपेंडेंसी के टाइप
ज़्यादातर बिल्ड के नियमों में अलग-अलग तरह की सामान्य डिपेंडेंसी तय करने के लिए, तीन एट्रिब्यूट होते हैं: srcs
, deps
, और data
. इस बारे में नीचे बताया गया है. ज़्यादा
जानकारी के लिए, सभी नियमों के लिए सामान्य एट्रिब्यूट देखें.
कई नियमों में, अलग-अलग तरह की डिपेंडेंसी के हिसाब से अलग-अलग एट्रिब्यूट भी होते हैं. जैसे, compiler
या resources
. इस बारे में जानकारी,
बिल्ड इनसाइक्लोपीडिया में दी गई है.
srcs
डिपेंडेंसी
सोर्स फ़ाइलें आउटपुट करने वाले नियम या नियमों के मुताबिक सीधे इस्तेमाल की गई फ़ाइलें.
deps
डिपेंडेंसी
हेडर फ़ाइलें, सिंबल, लाइब्रेरी, डेटा वगैरह उपलब्ध कराने वाले अलग-अलग कंपाइल किए गए मॉड्यूल की तरफ़ इशारा करने वाला नियम.
data
डिपेंडेंसी
बिल्ड टारगेट को ठीक से चलाने के लिए, कुछ डेटा फ़ाइलों की ज़रूरत पड़ सकती है. ये डेटा फ़ाइलें सोर्स कोड नहीं हैं: ये टारगेट को बनाने के तरीके पर असर नहीं डालती हैं. उदाहरण के लिए, इकाई टेस्ट किसी फ़ंक्शन के आउटपुट की तुलना फ़ाइल के कॉन्टेंट से कर सकता है. यूनिट टेस्ट बनाने के बाद, आपको फ़ाइल की ज़रूरत नहीं होती. हालांकि, टेस्ट करते समय आपको फ़ाइल की ज़रूरत पड़ती है. यह बात उन टूल पर भी लागू होती है जो प्रोग्राम चलाने के दौरान लॉन्च किए जाते हैं.
बिल्ड सिस्टम, टेस्ट को एक अलग डायरेक्ट्री में चलाता है, जहां सिर्फ़
data
के तौर पर सूची में शामिल फ़ाइलें उपलब्ध होती हैं. इसलिए, अगर किसी बाइनरी/लाइब्रेरी/टेस्ट व्यक्ति को चलाने के लिए कुछ फ़ाइलों की ज़रूरत है, तो data
में उनकी जानकारी दें या उसे बनाने के लिए कोई नियम बनाएं. उदाहरण के लिए:
# I need a config file from a directory named env:
java_binary(
name = "setenv",
...
data = [":env/default_env.txt"],
)
# I need test data from another directory
sh_test(
name = "regtest",
srcs = ["regtest.sh"],
data = [
"//data:file1.txt",
"//data:file2.txt",
...
],
)
ये फ़ाइलें रिलेटिव पाथ path/to/data/file
का इस्तेमाल करके उपलब्ध हैं. टेस्ट में,
टेस्ट की सोर्स डायरेक्ट्री के पाथ को जोड़कर, इन फ़ाइलों को देखा जा सकता है.
साथ ही, फ़ाइल फ़ोल्डर-रिलेटिव पाथ का भी इस्तेमाल किया जा सकता है, उदाहरण के लिए,
${TEST_SRCDIR}/workspace/path/to/data/file
.
डायरेक्ट्री का रेफ़रंस देने के लिए लेबल का इस्तेमाल करना
हमारी BUILD
फ़ाइलों पर एक नज़र डालते समय, आपको यह दिख सकता है कि कुछ data
लेबल, डायरेक्ट्री का इस्तेमाल करते हैं. ये लेबल, इन उदाहरणों की तरह /.
या /
पर खत्म होते हैं.
आपको इनका इस्तेमाल नहीं करना चाहिए:
इसका सुझाव नहीं दिया जाता —
data = ["//data/regression:unittest/."]
इसका सुझाव नहीं दिया जाता —
data = ["testdata/."]
इसका सुझाव नहीं दिया जाता —
data = ["testdata/"]
यह टेस्ट के लिए सुविधाजनक लगता है, खास तौर पर इसलिए, क्योंकि इससे टेस्ट में डायरेक्ट्री की सभी डेटा फ़ाइलों का इस्तेमाल किया जा सकता है.
लेकिन, ऐसा न करें. बदलाव के बाद सही इंक्रीमेंटल फिर से बिल्ड (और टेस्ट को फिर से चलाने) के लिए, बिल्ड सिस्टम को उन फ़ाइलों के पूरे सेट की जानकारी होनी चाहिए जो बिल्ड (या टेस्ट) के लिए इनपुट हैं. डायरेक्ट्री बनाने पर, बिल्ड सिस्टम फिर से सिर्फ़ तब काम करता है, जब डायरेक्ट्री अपने-आप बदलती है (फ़ाइलें जोड़ने या मिटाने की वजह से), लेकिन अलग-अलग फ़ाइलों में बदलाव का पता नहीं चल सकता, क्योंकि ये बदलाव बंद होने वाली डायरेक्ट्री पर कोई असर नहीं डालते.
बिल्ड सिस्टम के लिए इनपुट के तौर पर डायरेक्ट्री तय करने के बजाय, आपको उनमें मौजूद फ़ाइलों के सेट की गिनती करनी चाहिए. इसके लिए, साफ़ तौर पर या glob()
फ़ंक्शन का इस्तेमाल करें. (glob()
को बार-बार होने वाला बनाने के लिए, **
का इस्तेमाल करें.)
इसका सुझाव दिया जाता है — data = glob(["testdata/**"])
माफ़ करें, कुछ मामलों में डायरेक्ट्री लेबल का इस्तेमाल करना ज़रूरी है.
उदाहरण के लिए, अगर testdata
डायरेक्ट्री में ऐसी फ़ाइलें हैं जिनके नाम
लेबल सिंटैक्स के मुताबिक नहीं हैं, तो
फ़ाइलों को साफ़ तौर पर इन्युमेशन करें या
glob()
फ़ंक्शन का इस्तेमाल करने से अमान्य लेबल की गड़बड़ी होती है. इस मामले में आपको डायरेक्ट्री लेबल का इस्तेमाल करना चाहिए, लेकिन ऊपर बताए गए रीबिल्ड के गलत इस्तेमाल के जोखिम से सावधान रहें.
अगर आपको डायरेक्ट्री लेबल का इस्तेमाल करना है, तो ध्यान रखें कि आप किसी रिलेटिव ../
पाथ से पैरंट पैकेज का रेफ़रंस नहीं दे सकते. इसके बजाय, //data/regression:unittest/.
जैसे ऐब्सलूट पाथ का इस्तेमाल करें.
कोई भी बाहरी नियम, जैसे कि टेस्ट, जिसे कई फ़ाइलों का इस्तेमाल करना है, उसे साफ़ तौर पर बताना होगा कि वह नियम इन सभी पर निर्भर है. BUILD
फ़ाइल में फ़ाइलों को एक साथ ग्रुप करने के लिए, filegroup()
का इस्तेमाल किया जा सकता है:
filegroup(
name = 'my_data',
srcs = glob(['my_unittest_data/*'])
)
इसके बाद, अपनी जांच में डेटा डिपेंडेंसी के तौर पर, my_data
लेबल का रेफ़रंस दिया जा सकता है.
फ़ाइलें बनाएं | वीडियो किसको दिखे |