अगर A
को बिल्ड या रन करने के समय B
की ज़रूरत है, तो टारगेट A
, टारगेट B
पर निर्भर करता है. यह पर निर्भर करता है संबंध, टारगेट के ऊपर निर्देशित एक्सीलिक ग्राफ़
(DAG) बनाता है और इसे डिपेंडेंसी ग्राफ़ कहा जाता है.
किसी टारगेट की डायरेक्ट डिपेंडेंसी वे दूसरे टारगेट होते हैं जो डिपेंडेंसी ग्राफ़ में एक लंबाई वाले पाथ से ऐक्सेस किए जा सकते हैं. किसी टारगेट की ट्रांज़िशन डिपेंडेंसी, वे टारगेट होते हैं जिन पर वह ग्राफ़ के किसी भी लंबाई वाले पाथ के ज़रिए निर्भर करता है.
असल में, बिल्ड के संदर्भ में, डिपेंडेंसी के दो ग्राफ़ होते हैं. पहला, असल डिपेंडेंसी का ग्राफ़ और दूसरा, एलान की गई डिपेंडेंसी का ग्राफ़. ज़्यादातर समय, दोनों ग्राफ़ एक जैसे होते हैं. इसलिए, इनमें अंतर करने की ज़रूरत नहीं होती. हालांकि, नीचे दी गई बातचीत के लिए यह फ़र्क़ जानना ज़रूरी है.
असल और बताई गई डिपेंडेंसी
टारगेट X
, टारगेट Y
पर असल में निर्भर होता है. ऐसा तब होता है, जब X
को सही तरीके से बनाने के लिए Y
मौजूद, बनाया गया हो, और अप-टू-डेट हो. बिल्ट का मतलब, जनरेट, प्रोसेस, कंपाइल, लिंक, संग्रहित, कंप्रेस, या किसी भी तरह के ऐसे टास्क से हो सकता है जो आम तौर पर बिल्ड के दौरान होते हैं.
अगर X
के पैकेज में X
से Y
तक की डिपेंडेंसी एज होती है, तो टारगेट X
में टारगेट Y
पर एलान की गई डिपेंडेंसी होती है.
सही बिल्ड के लिए, असल डिपेंडेंसी A का ग्राफ़, डिपेंडेंसी के तौर पर बताई गई चीज़ों D के ग्राफ़ का सबसे छोटा ग्राफ़ होना चाहिए. इसका मतलब है कि A में सीधे तौर पर जुड़े नोड x --> y
के हर जोड़े को D में भी सीधे तौर पर जोड़ा जाना चाहिए. यह कहा जा सकता है कि D, A का ज़्यादा अनुमान है.
BUILD
फ़ाइल लिखने वाले लोगों को, बिल्ड सिस्टम के लिए हर नियम की सभी असल डायरेक्ट डिपेंडेंसी के बारे में साफ़ तौर पर बताना चाहिए.
इस सिद्धांत को न समझ पाने पर, व्यवहार के बारे में जानकारी नहीं मिलती है: बिल्ड शायद कामयाब न हो पाए, लेकिन इससे भी बुरा यह हो सकता है कि बिल्ड पहले की कुछ कार्रवाइयों पर निर्भर हो या फिर टारगेट के बारे में तय की गई ट्रांज़िटिव डिपेंडेंसी पर निर्भर करता हो. बेज़ल, उन डिपेंडेंसी और रिपोर्ट से जुड़ी गड़बड़ियों की जांच करता है जो मौजूद नहीं हैं. हालांकि, सभी मामलों में यह जांच पूरी नहीं की जा सकती.
आपको सीधे तौर पर इंपोर्ट नहीं की गई हर चीज़ को सूची में शामिल करने की ज़रूरत नहीं है. ऐसा करने की कोशिश भी नहीं करनी चाहिए. भले ही, 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
का इस्तेमाल करके उपलब्ध हैं. टेस्ट में, इन फ़ाइलों का रेफ़रंस देने के लिए, टेस्ट की सोर्स डायरेक्ट्री और Workspace के हिसाब से पाथ को जोड़ें. उदाहरण के लिए, ${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
लेबल का रेफ़रंस दिया जा सकता है.
BUILD फ़ाइलें | किसको दिखे |