निर्भरताएं

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

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

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

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

असल और डिपेंडेंसी डिपेंडेंसी

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

अगर टारगेट किए गए X की वैल्यू X के पैकेज की X से Y है, तो टारगेट X का टारगेट Y पर एलान किया गया डिपेंडेंसी है.

सही बिल्ड के लिए, असल डिपेंडेंसी A का ग्राफ़, डिपेंडेंसी डिपेंडेंसी के ग्राफ़ का सब-ग्राफ़ होना चाहिए D. इसका मतलब है कि Aमें सीधे तौर से जुड़े नोड x --> yके हर जोड़े को, Dमें सीधे तौर पर जोड़ा जाना चाहिए. यह कहा जा सकता है कि D, A का अनुमान है.

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

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

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

तय किया गया डिपेंडेंसी अब असल डिपेंडेंसी से ज़्यादा काम नहीं करता. इस वजह से, यह ठीक हो सकता है, क्योंकि दो ग्राफ़ में, अस्थायी रूप से बंद होने की जानकारी बराबर होती है, लेकिन समस्या मास्क की तरह होती है: 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 से कनेक्ट नहीं होता है
असल डिपेंडेंसी ग्राफ़

पेश किया गया डिपेंडेंसी ग्राफ़ अब असल डिपेंडेंसी का एक अनुमान नहीं है, भले ही कुछ समय के लिए बंद हो, बिल्ड के काम न करने की संभावना हो.

हो सकता है कि चरण 2 में a से c तक वास्तविक निर्भरता, BUILD फ़ाइल में ठीक से बताई गई हो.

डिपेंडेंसी के टाइप

बिल्ड के ज़्यादातर नियमों में अलग-अलग तरह की सामान्य निर्भरताओं के बारे में बताने के लिए तीन एट्रिब्यूट होते हैं: srcs, deps, और data. नीचे इनके बारे में बताया गया है. ज़्यादा जानकारी के लिए, सभी नियमों से जुड़े एट्रिब्यूट देखें.

कई नियमों में, खास तरह की डिपेंडेंसी के लिए अतिरिक्त एट्रिब्यूट भी होते हैं. उदाहरण के लिए, compiler या resources. इस बारे में ज़्यादा जानकारी, Build Encyclopedia में दी गई है.

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 लेबल का रेफ़रंस दिया जा सकता है.

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