डिपेंडेंसी

समस्या की शिकायत करें सोर्स देखें

टारगेट A, टारगेट B पर निर्भर करता है. ऐसा तब होता है, जब बिल्ड या उसे लागू करने के समय A तक B की ज़रूरत हो. यह पर निर्भर करता है संबंध, टारगेट के ऊपर निर्देशित एक्सीलिक ग्राफ़ (DAG) बनाता है और इसे डिपेंडेंसी ग्राफ़ कहा जाता है.

टारगेट की डायरेक्ट डिपेंडेंसी वे दूसरे टारगेट होते हैं जिन्हें डिपेंडेंसी ग्राफ़ में लंबाई 1 के पाथ से हासिल किया जा सकता है. टारगेट की ट्रांज़िव डिपेंडेंसी वे टारगेट होते हैं जिन पर यह ग्राफ़ में किसी भी लंबाई के पाथ के ज़रिए निर्भर करती है.

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

असल और तय की गई डिपेंडेंसी

X को सही तरीके से बनाने के लिए, Y मौजूद होने, बिल्ट-इन, और अप-टू-डेट होने पर, टारगेट X, टारगेट Y पर पूरी तरह से निर्भर होता है. पहले से मौजूद का मतलब जनरेट, प्रोसेस, कंपाइल, लिंक, संग्रहित, कंप्रेस किए गए, एक्ज़ीक्यूट किए गए या किसी ऐसे टास्क से हो सकता है जो आम तौर पर बिल्ड के दौरान होता है.

अगर X के पैकेज में, 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();
}
      
a, b, और c को जोड़ने वाले ऐरो के साथ डिपेंडेंसी ग्राफ़ का एलान किया गया
एलान किया गया डिपेंडेंसी ग्राफ़
डिपेंडेंसी ग्राफ़, जो एलान किए गए डिपेंडेंसी ग्राफ़ से मेल खाता है. इस ग्राफ़ में a, b, और c ऐरो के निशान हैं
असल डिपेंडेंसी ग्राफ़

तय की गई डिपेंडेंसी, असल डिपेंडेंसी से ज़्यादा अनुमानित होती हैं. सब ठीक है.

2. ऐसी डिपेंडेंसी जोड़ना जिसका एलान नहीं किया गया है

जब कोई व्यक्ति a में कोड जोड़ता है, जो c पर सीधे तौर पर असल डिपेंडेंसी बनाता है, लेकिन बिल्ड फ़ाइलa/BUILD में इस बारे में जानकारी नहीं देता है, तो देर से होने वाला खतरा पैदा होता है.

a / a.in  
        import b;
        import c;
        b.foo();
        c.garply();
      
 
a, b, और c को जोड़ने वाले ऐरो के साथ डिपेंडेंसी ग्राफ़ का एलान किया गया
एलान किया गया डिपेंडेंसी ग्राफ़
a, b, और c को जोड़ने वाले ऐरो के साथ असल डिपेंडेंसी ग्राफ़. अब ऐरो से A को C से भी कनेक्ट किया जा सकता है. यह, एलान किए गए डिपेंडेंसी ग्राफ़ से मेल नहीं खाता
असल डिपेंडेंसी ग्राफ़

तय की गई डिपेंडेंसी अब असल डिपेंडेंसी से ज़्यादा अनुमानित नहीं होती हैं. यह ठीक हो सकता है, क्योंकि दो ग्राफ़ के ट्रांज़िटिव क्लोज़िंग बराबर हैं, लेकिन एक समस्या को छिपा देता है: 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 और b को जोड़ने वाले ऐरो के साथ डिपेंडेंसी ग्राफ़ का एलान किया गया.
                  b अब c से कनेक्ट नहीं होता है, जिससे c का कनेक्शन टूटता है
एलान किया गया डिपेंडेंसी ग्राफ़
असल डिपेंडेंसी ग्राफ़, जो b और c से कनेक्ट दिखाता है,
                  लेकिन b अब c से कनेक्ट नहीं होता
असल डिपेंडेंसी ग्राफ़

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

यह पक्का करके इस समस्या को टाला जा सकता था कि दूसरे चरण में शुरू की गई 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 लेबल का रेफ़रंस दिया जा सकता है.

बिल्ड फ़ाइलें किसे दिखे