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

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

वर्कस्पेस डायरेक्ट्री में मौजूद WORKSPACE फ़ाइल या WORKSPACE.bazel फ़ाइल से Bazel को दूसरे प्रोजेक्ट के सोर्स ऐक्सेस करने का तरीका पता चलता है. इन दूसरे प्रोजेक्ट में, अपने टारगेट वाली एक या उससे ज़्यादा 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/ के टारगेट पर निर्भर रहना है. दोनों प्रोजेक्ट में Bazel का इस्तेमाल होता है. इसलिए, आप अपने सहकर्मी के प्रोजेक्ट को बाहरी निर्भरता के तौर पर जोड़ सकते हैं. इसके बाद, आपके सहकर्मी के प्रोजेक्ट में आपकी अपनी 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 रिपॉज़िटरी से आर्टफ़ैक्ट डाउनलोड करने और उन्हें 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 रिपॉज़िटरी को किसी लोकल डायरेक्ट्री में बदला जा सकता है. इसमें आप आसानी से बदलाव कर सकते हैं.
  • वेंडर बनाना. अगर आप किसी ऐसे माहौल में हैं जहां नेटवर्क कॉल नहीं किए जा सकते, तो नेटवर्क पर आधारित रिपॉज़िटरी के नियमों को बदलें और स्थानीय डायरेक्ट्री पर ले जाएं.

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

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

आईपीवी6 के साथ काम करता है

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

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

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

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

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

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

लेआउट

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

ls $(bazel info output_base)/external

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

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

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

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

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

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

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

डेटा स्टोर करने के नियम

आम तौर पर, डेटा स्टोर करने की जगह के नियम के लिए ये ज़िम्मेदार होते हैं:

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

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

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

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

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