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

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

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

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

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

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

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

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

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

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

अन्य Basel प्रोजेक्ट के आधार पर

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

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

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

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

नॉन-बेज़ल प्रोजेक्ट के आधार पर

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

उदाहरण के लिए, मान लें कि आपको किसी प्रोजेक्ट 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(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 के साथ काम करने की सुविधा

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

  • --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 होने की संभावना कम हो जाती है.

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

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

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

लेआउट

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

ls $(bazel info output_base)/external

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

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

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

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

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

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

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

डेटा स्टोर करने की जगह के नियम

आम तौर पर, रिपॉज़िटरी का नियम इनके लिए ज़िम्मेदार होना चाहिए:

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

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

git_repository और new_git_repository से http_archive को प्राथमिकता दें. इसकी वजहें ये हैं:

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

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