बाहरी डिपेंडेंसी के साथ काम करना

किसी समस्या की शिकायत करें सोर्स देखें Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bazel, दूसरे प्रोजेक्ट के टारगेट पर निर्भर हो सकता है. इन अन्य प्रोजेक्ट की डिपेंडेंसी को बाहरी डिपेंडेंसी कहा जाता है.

फ़ाइल फ़ोल्डर डायरेक्ट्री में मौजूद WORKSPACE फ़ाइल (या WORKSPACE.bazel फ़ाइल) से Basel को पता चलता है कि दूसरे प्रोजेक्ट के सोर्स कैसे डाउनलोड किए जा सकते हैं. इन अन्य प्रोजेक्ट में, एक या उससे ज़्यादा BUILD फ़ाइलें हो सकती हैं. इनमें अपने टारगेट भी हो सकते हैं. मुख्य प्रोजेक्ट में मौजूद BUILD फ़ाइलें, WORKSPACE फ़ाइल में मौजूद उनके नाम का इस्तेमाल करके, इन बाहरी टारगेट पर निर्भर हो सकती हैं.

उदाहरण के लिए, मान लें कि किसी सिस्टम पर दो प्रोजेक्ट हैं:

/
  home/
    user/
      project1/
        WORKSPACE
        BUILD
        srcs/
          ...
      project2/
        WORKSPACE
        BUILD
        my-libs/

अगर project1 को /home/user/project2/BUILD में बताए गए टारगेट :foo पर निर्भर रहना है, तो वह बता सकता है कि project2 नाम का रिपॉज़िटरी /home/user/project2 पर मिल सकता है. इसके बाद, /home/user/project1/BUILD में मौजूद टारगेट, @project2//:foo पर निर्भर हो सकते हैं.

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

बाहरी डिपेंडेंसी के काम करने वाले टाइप

बाहरी डिपेंडेंसी के कुछ बुनियादी टाइप इस्तेमाल किए जा सकते हैं:

अन्य Bazel प्रोजेक्ट पर निर्भर करता है

अगर आपको किसी दूसरे Bazel प्रोजेक्ट के टारगेट का इस्तेमाल करना है, तो local_repository, git_repository या http_archive का इस्तेमाल करें. इससे, टारगेट को लोकल फ़ाइल सिस्टम से लिंक किया जा सकता है, किसी git रिपॉज़िटरी का रेफ़रंस दिया जा सकता है या उसे डाउनलोड किया जा सकता है.

उदाहरण के लिए, मान लें कि आप my-project/ प्रोजेक्ट पर काम कर रहे हैं और आपको अपने सहकर्मी के coworkers-project/ प्रोजेक्ट के टारगेट पर निर्भर रहना है. दोनों प्रोजेक्ट, Basel का इस्तेमाल करते हैं. इसलिए, आपके पास अपने सहकर्मी के प्रोजेक्ट को बाहरी डिपेंडेंसी के तौर पर जोड़ा जा सकता है. इसके बाद, आपके सहकर्मी ने आपकी BUILD फ़ाइलों से जो टारगेट तय किया है उसका इस्तेमाल किया जा सकता है. आपको my_project/WORKSPACE में यह जोड़ना होगा:

local_repository(
    name = "coworkers_project",
    path = "/path/to/coworkers-project",
)

अगर आपके सहकर्मी का कोई टारगेट //foo:bar है, तो आपके प्रोजेक्ट में इसे @coworkers_project//foo:bar के तौर पर दिखाया जा सकता है. बाहरी प्रोजेक्ट के नाम, वर्कस्पेस के मान्य नाम होने चाहिए.

Bazel प्रोजेक्ट के अलावा अन्य प्रोजेक्ट के हिसाब से

new_ से शुरू होने वाले नियमों, जैसे कि new_local_repository की मदद से, उन प्रोजेक्ट के टारगेट बनाए जा सकते हैं जिनमें Bazel का इस्तेमाल नहीं किया जाता.

उदाहरण के लिए, मान लें कि आप किसी प्रोजेक्ट, my-project/ पर काम कर रहे हैं और आपको अपने सहकर्मी के प्रोजेक्ट, coworkers-project/ पर निर्भर रहना है. आपके सहकर्मी का प्रोजेक्ट, बिल्ड करने के लिए make का इस्तेमाल करता है. हालांकि, आपको उससे जनरेट की गई किसी .so फ़ाइल का इस्तेमाल करना है. ऐसा करने के लिए, my_project/WORKSPACE में ये जोड़ें:

new_local_repository(
    name = "coworkers_project",
    path = "/path/to/coworkers-project",
    build_file = "coworker.BUILD",
)

build_file, मौजूदा प्रोजेक्ट पर ओवरले करने के लिए BUILD फ़ाइल के बारे में बताता है, उदाहरण के लिए:

cc_library(
    name = "some-lib",
    srcs = glob(["**"]),
    visibility = ["//visibility:public"],
)

इसके बाद, अपने प्रोजेक्ट की BUILD फ़ाइलों में मौजूद @coworkers_project//:some-lib का इस्तेमाल किया जा सकता है.

बाहरी पैकेज के हिसाब से

Maven आर्टफ़ैक्ट और डेटा स्टोर करने की जगहें

Maven के डेटा को स्टोर करने की जगहों से आर्टफ़ैक्ट डाउनलोड करने और उन्हें Java डिपेंडेंसी के तौर पर उपलब्ध कराने के लिए, नियमों के सेट rules_jvm_external का इस्तेमाल करें.

डिपेंडेंसी फ़ेच करना

डिफ़ॉल्ट रूप से, bazel build के दौरान ज़रूरत के हिसाब से बाहरी डिपेंडेंसी फ़ेच की जाती हैं. अगर आपको टारगेट के किसी खास सेट के लिए ज़रूरी डिपेंडेंसी को पहले से लोड करना है, तो bazel fetch का इस्तेमाल करें. सभी बाहरी डिपेंडेंसी को बिना किसी शर्त के फ़ेच करने के लिए, bazel sync का इस्तेमाल करें. फ़ेच किए गए रिपॉज़िटरी, आउटपुट बेस में सेव किए जाते हैं. इसलिए, हर वर्कस्पेस के लिए फ़ेचिंग की जाती है.

शैडो करने वाली डिपेंडेंसी

हमारा सुझाव है कि जहां तक हो सके, अपने प्रोजेक्ट में एक वर्शन की नीति का इस्तेमाल करें. यह उन डिपेंडेंसी के लिए ज़रूरी है जिन्हें आपने कॉम्पाइल किया है और जो आखिर में आपकी फ़ाइनल बाइनरी में शामिल हो जाती हैं. हालांकि, जिन मामलों में ऐसा नहीं है उनके लिए, डिपेंडेंसी को छिपाया जा सकता है. यह उदाहरण देखें:

मेरा प्रोजेक्ट/वर्कस्पेस

workspace(name = "myproject")

local_repository(
    name = "A",
    path = "../A",
)
local_repository(
    name = "B",
    path = "../B",
)

A/WORKSPACE

workspace(name = "A")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "testrunner",
    urls = ["https://github.com/testrunner/v1.zip"],
    sha256 = "...",
)

बी/वर्कस्पेस

workspace(name = "B")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "testrunner",
    urls = ["https://github.com/testrunner/v2.zip"],
    sha256 = "..."
)

डिपेंडेंसी A और B, दोनों testrunner पर निर्भर करती हैं. हालांकि, ये testrunner के अलग-अलग वर्शन पर निर्भर करती हैं. इन टेस्ट रनर के myproject में एक साथ काम करने से कोई समस्या नहीं होती. हालांकि, इनका नाम एक जैसा होने की वजह से, ये एक-दूसरे से टकराते हैं. दोनों डिपेंडेंसी का एलान करने के लिए, myproject/WORKSPACE को अपडेट करें:

workspace(name = "myproject")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "testrunner-v1",
    urls = ["https://github.com/testrunner/v1.zip"],
    sha256 = "..."
)
http_archive(
    name = "testrunner-v2",
    urls = ["https://github.com/testrunner/v2.zip"],
    sha256 = "..."
)
local_repository(
    name = "A",
    path = "../A",
    repo_mapping = {"@testrunner" : "@testrunner-v1"}
)
local_repository(
    name = "B",
    path = "../B",
    repo_mapping = {"@testrunner" : "@testrunner-v2"}
)

इस तरीके का इस्तेमाल, डायमंड को जोड़ने के लिए भी किया जा सकता है. उदाहरण के लिए, अगर A और B के पास एक ही डिपेंडेंसी है, लेकिन उसे अलग-अलग नामों से कॉल किया जाता है, तो उन डिपेंडेंसी को myproject/WORKSPACE में जोड़ा जा सकता है.

कमांड लाइन से रिपॉज़िटरी को बदलना

कमांड-लाइन से, किसी लोकल रिपॉज़िटरी को पहले से तय रिपॉज़िटरी से बदलने के लिए, --override_repository फ़्लैग का इस्तेमाल करें. इस फ़्लैग का इस्तेमाल करने से, आपके सोर्स कोड में बदलाव किए बिना, बाहरी रिपॉज़िटरी के कॉन्टेंट में बदलाव होता है.

उदाहरण के लिए, @foo को लोकल डायरेक्ट्री /path/to/local/foo में बदलने के लिए, --override_repository=foo=/path/to/local/foo फ़्लैग को पास करें.

इस्तेमाल के कुछ उदाहरणों में ये शामिल हैं:

  • डीबग करने से जुड़ी समस्याएं. उदाहरण के लिए, किसी http_archive रिपॉज़िटरी को किसी लोकल डायरेक्ट्री से बदला जा सकता है, जहां बदलाव आसानी से किए जा सकते हैं.
  • वेंडरिंग. अगर आप किसी ऐसे माहौल में हैं जहां नेटवर्क कॉल नहीं किए जा सकते, तो नेटवर्क पर आधारित रिपॉज़िटरी के नियमों को बदलकर, लोकल डायरेक्ट्री पर जाएं.

प्रॉक्सी का इस्तेमाल करना

Basel, HTTPS_PROXY और HTTP_PROXY एनवायरमेंट वैरिएबल से प्रॉक्सी पते चुनेगा और उनका इस्तेमाल एचटीटीपी/एचटीटीपीएस फ़ाइलों (अगर बताया गया है) को डाउनलोड करने के लिए करेगा.

आईपीवी6 के साथ काम करने की सुविधा

सिर्फ़ IPv6 वाली मशीनों पर, Bazel बिना किसी बदलाव के डिपेंडेंसी डाउनलोड कर पाएगा. हालांकि, ड्यूअल-स्टैक IPv4/IPv6 मशीनों पर, Bazel उसी कॉन्वेंशन का पालन करता है जो Java करता है: अगर IPv4 चालू है, तो IPv4 को प्राथमिकता दी जाती है. कुछ मामलों में, उदाहरण के लिए, जब आईपीवी4 नेटवर्क, बाहरी पतों को हल नहीं कर पाता/उन तक नहीं पहुंच पाता, तो इससे Network unreachable अपवाद और बिल्ड में गड़बड़ियां हो सकती हैं. इन मामलों में, java.net.preferIPv6Addresses=true सिस्टम प्रॉपर्टी का इस्तेमाल करके, IPv6 को प्राथमिकता देने के लिए Bazel के व्यवहार को बदला जा सकता है. खास तौर पर:

  • --host_jvm_args=-Djava.net.preferIPv6Addresses=true स्टार्टअप विकल्प का इस्तेमाल करें. उदाहरण के लिए, अपनी .bazelrc फ़ाइल में यह लाइन जोड़ें:

    startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true

  • अगर आपको ऐसे Java बिल्ड टारगेट चलाने हैं जिन्हें इंटरनेट से कनेक्ट करना भी ज़रूरी है (इंटिग्रेशन टेस्ट के लिए कभी-कभी ऐसा करना ज़रूरी होता है), तो --jvmopt=-Djava.net.preferIPv6Addresses=true टूल फ़्लैग का भी इस्तेमाल करें. उदाहरण के लिए, अपनी .bazelrc फ़ाइल में यह लाइन जोड़ें:

    build --jvmopt=-Djava.net.preferIPv6Addresses

  • अगर rules_jvm_external का इस्तेमाल किया जा रहा है, तो उदाहरण के लिए, डिपेंडेंसी वर्शन रिज़ॉल्यूशन के लिए, COURSIER_OPTS एनवायरमेंट वैरिएबल में -Djava.net.preferIPv6Addresses=true भी जोड़ें. इससे Coursier के लिए JVM के विकल्प उपलब्ध कराए जा सकेंगे

ट्रांसिटिव डिपेंडेंसी

Baज़ल, आपकी WORKSPACE फ़ाइल में दी गई डिपेंडेंसी को सिर्फ़ पढ़ता है. अगर आपका प्रोजेक्ट (A), ऐसे दूसरे प्रोजेक्ट (B) पर निर्भर है जिसके लिए WORKSPACE फ़ाइल में किसी तीसरे प्रोजेक्ट (C) पर डिपेंडेंसी दी गई है, तो आपको अपने प्रोजेक्ट की WORKSPACE फ़ाइल में B और C, दोनों को जोड़ना होगा. यह ज़रूरी शर्त, WORKSPACE फ़ाइल के साइज़ को गुनगुना सकती है. हालांकि, इससे वर्शन 1.0 में C और दूसरे में C को 2.0 से शामिल करने की संभावना कम हो जाती है.

बाहरी डिपेंडेंसी को कैश मेमोरी में सेव करना

डिफ़ॉल्ट रूप से, Basel की डेफ़िनिशन में बदलाव होने पर ही, वे बाहरी डिपेंडेंसी को फिर से डाउनलोड करेंगे. परिभाषा में बताई गई फ़ाइलों (जैसे, पैच या BUILD फ़ाइलें) में किए जाने वाले बदलावों को भी बेज़ल स्वीकार करता है.

फिर से डाउनलोड करने के लिए, bazel sync का इस्तेमाल करें.

लेआउट

बाहरी डिपेंडेंसी, आउटपुट बेस में सब-डायरेक्ट्री external के नीचे मौजूद डायरेक्ट्री में डाउनलोड की जाती हैं. लोकल रिपॉज़िटरी के मामले में, नई डायरेक्ट्री बनाने के बजाय, वहां एक सिमलिंक बनाया जाता है. external डायरेक्ट्री देखने के लिए, यह कमांड चलाएं:

ls $(bazel info output_base)/external

ध्यान दें कि bazel clean को चलाने से, बाहरी डायरेक्ट्री असल में नहीं मिटेगी. सभी बाहरी आर्टफ़ैक्ट हटाने के लिए, bazel clean --expunge का इस्तेमाल करें.

ऑफ़लाइन बिल्ड

कभी-कभी, किसी बिल्ड को ऑफ़लाइन चलाना ज़रूरी या बेहतर होता है. bazel fetch या bazel sync का इस्तेमाल करके, ज़रूरी रिपॉज़िटरी को पहले से लोड करने से, हवाई यात्रा जैसे सामान्य इस्तेमाल के उदाहरणों के लिए काफ़ी हो सकता है. इसके अलावा, --nofetch विकल्प का इस्तेमाल करके, बिल्ड के दौरान अन्य रिपॉज़िटरी को फ़ेच करने की सुविधा बंद की जा सकती है.

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

Bazel खुद इस तकनीक का इस्तेमाल करके, डिस्ट्रिब्यूशन आर्टफ़ैक्ट से ऑफ़लाइन बूटस्ट्रैप करता है. यह ऐसा, distdir_tar में ज़रूरी सभी बाहरी डिपेंडेंसी इकट्ठा करके करता है.

हालांकि, bazel, रिपॉज़िटरी के नियमों में मनमुताबिक निर्देशों को लागू करने की अनुमति देता है. ऐसा करते समय, यह पता नहीं चलता कि वे निर्देश नेटवर्क पर कॉल करते हैं या नहीं. इसलिए, bazel में बिल्कुल ऑफ़लाइन बने रहने के लिए, कोई विकल्प नहीं है. इसलिए, अगर कोई बिल्ड सही तरीके से काम कर रहा है, तो ऑफ़लाइन टेस्ट के लिए नेटवर्क को बाहरी ब्लॉक करना ज़रूरी होता है, जैसा कि बेज़ल अपने बूटस्ट्रैप टेस्ट में करता है.

सबसे सही तरीके

रिपॉज़िटरी के नियम

आम तौर पर, रिपॉज़िटरी के नियम से ये काम किए जाने चाहिए:

  • सिस्टम सेटिंग को पहचानकर, उन्हें फ़ाइलों पर लिखा जा सकता है.
  • सिस्टम में कहीं और संसाधन ढूंढना.
  • यूआरएल से रिसॉर्स डाउनलोड करना.
  • बाहरी रिपॉज़िटरी डायरेक्ट्री में BUILD फ़ाइलों को जनरेट या सिमलिंक करना.

अगर हो सके, तो repository_ctx.execute का इस्तेमाल न करें. उदाहरण के लिए, अगर किसी ऐसी C++ लाइब्रेरी का इस्तेमाल किया जा रहा है जो Bazel के बजाय Make का इस्तेमाल करके बनाई गई है, तो ctx.execute(["make"]) को चलाने के बजाय, repository_ctx.download() का इस्तेमाल करें. इसके बाद, BUILD फ़ाइल लिखें, ताकि लाइब्रेरी बनाई जा सके.

git_repository और new_git_repository के बजाय, http_archive का इस्तेमाल करें. इसकी वजहें ये हैं:

  • Git रिपॉज़िटरी के नियम, सिस्टम git(1) पर निर्भर करते हैं. वहीं, एचटीटीपी डाउनलोडर को Bazel में बनाया गया है और इसमें सिस्टम की कोई डिपेंडेंसी नहीं है.
  • http_archive, मिरर के तौर पर urls की सूची के साथ काम करता है. वहीं, git_repository सिर्फ़ एक remote के साथ काम करता है.
  • http_archive, डेटा स्टोर करने की कैश मेमोरी के साथ काम करता है, लेकिन git_repository के साथ काम नहीं करता. ज़्यादा जानकारी के लिए, #5116 देखें.

bind() का इस्तेमाल न करें. इसकी समस्याओं और विकल्पों के बारे में ज़्यादा जानने के लिए, "bind को हटाने पर विचार करें" लेख पढ़ें.