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 के अलावा अन्य प्रोजेक्ट पर निर्भरता
- बाहरी पैकेज पर निर्भरता
अन्य 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
है, तो आपका प्रोजेक्ट इसे //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
का इस्तेमाल करें.
फ़ेच की गई रिपॉज़िटरी आउटपुट बेस में सेव होती हैं. इसलिए, फ़ेच करने की प्रोसेस हर फ़ाइल फ़ोल्डर के हिसाब से होती है.
शैडोइंग डिपेंडेंसी
हमारा सुझाव है कि जहां तक हो सके, अपने प्रोजेक्ट में एक ही वर्शन की नीति का इस्तेमाल करें. यह उन डिपेंडेंसी के लिए ज़रूरी है जिन्हें कंपाइल किया जाता है और जो आपकी फ़ाइनल बाइनरी में शामिल होती हैं. हालांकि, जिन मामलों में ऐसा नहीं होता है उनमें शैडो डिपेंडेंसी का इस्तेमाल किया जा सकता है. यह उदाहरण देखें:
myproject/WORKSPACE
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 = "...",
)
B/WORKSPACE
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
एनवायरमेंट वैरिएबल से प्रॉक्सी पते चुन लेगा. साथ ही, इनका इस्तेमाल एचटीटीपी/एचटीटीपीएस फ़ाइलें डाउनलोड करने के लिए करेगा (अगर बताया गया है).
IPv6 के साथ काम करने वाला वर्शन
सिर्फ़ IPv6 वाले कंप्यूटरों पर, Bazel बिना किसी बदलाव के डिपेंडेंसी डाउनलोड कर पाएगा. हालांकि, ड्यूअल-स्टैक IPv4/IPv6 मशीनों पर, Bazel उसी
कन्वेंशन का पालन करता है जिसका पालन Java करता है: अगर IPv4 चालू है, तो IPv4 को प्राथमिकता दी जाती है. कुछ मामलों में, जैसे कि जब IPv4 नेटवर्क बाहरी पतों को हल/पहुंच नहीं कर पाता है, तो इससे Network unreachable
अपवाद हो सकते हैं और बिल्ड फ़ेल हो सकते हैं.
इन मामलों में, java.net.preferIPv6Addresses=true
सिस्टम प्रॉपर्टी का इस्तेमाल करके, Bazel के डिफ़ॉल्ट व्यवहार को बदला जा सकता है, ताकि वह आईपीवी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 के विकल्प उपलब्ध कराएं
ट्रांज़िटिव डिपेंडेंसी
Bazel सिर्फ़ उन डिपेंडेंसी को पढ़ता है जो आपकी WORKSPACE
फ़ाइल में शामिल हैं. अगर आपका प्रोजेक्ट (A
) किसी ऐसे प्रोजेक्ट (B
) पर निर्भर करता है जिसकी WORKSPACE
फ़ाइल में किसी तीसरे प्रोजेक्ट (C
) पर निर्भरता की जानकारी दी गई है, तो आपको अपने प्रोजेक्ट की WORKSPACE
फ़ाइल में B
और C
, दोनों को जोड़ना होगा. इस ज़रूरी शर्त की वजह से, WORKSPACE
फ़ाइल का साइज़ बढ़ सकता है. हालांकि, इससे इस बात की संभावना कम हो जाती है कि एक लाइब्रेरी में C
का वर्शन 1.0 और दूसरी लाइब्रेरी में C
का वर्शन 2.0 शामिल हो.
बाहरी डिपेंडेंसी को कैश मेमोरी में सेव करना
डिफ़ॉल्ट रूप से, Bazel सिर्फ़ तब बाहरी डिपेंडेंसी को फिर से डाउनलोड करेगा, जब उनकी परिभाषा में बदलाव होगा. Bazel, परिभाषा में शामिल फ़ाइलों (जैसे कि पैच या BUILD
फ़ाइलें) में किए गए बदलावों को भी ध्यान में रखता है.
फिर से डाउनलोड करने के लिए, bazel sync
का इस्तेमाल करें.
लेआउट
सभी बाहरी डिपेंडेंसी, आउटपुट बेस में मौजूद सबडायरेक्ट्री external
के तहत किसी डायरेक्ट्री में डाउनलोड की जाती हैं. लोकल रिपॉज़िटरी के मामले में, नई डायरेक्ट्री बनाने के बजाय वहां एक सिंबॉलिक लिंक बनाया जाता है.
external
डायरेक्ट्री देखने के लिए, यह कमांड चलाएं:
ls $(bazel info output_base)/external
ध्यान दें कि bazel clean
चलाने से, बाहरी डायरेक्ट्री असल में नहीं मिटेगी. सभी बाहरी आर्टफ़ैक्ट हटाने के लिए, bazel clean --expunge
का इस्तेमाल करें.
ऑफ़लाइन बिल्ड
कभी-कभी, ऑफ़लाइन तरीके से बिल्ड चलाना ज़रूरी या फ़ायदेमंद होता है. फ़्लाइट में यात्रा करने जैसे सामान्य इस्तेमाल के मामलों में, bazel fetch
या bazel sync
का इस्तेमाल करके ज़रूरी रिपॉज़िटरी को prefetching किया जा सकता है. इसके अलावा, --nofetch
विकल्प का इस्तेमाल करके, बिल्ड के दौरान अन्य रिपॉज़िटरी को फ़ेच करने की सुविधा बंद की जा सकती है.
अगर आपको पूरी तरह से ऑफ़लाइन बिल्ड बनाने हैं और ज़रूरी फ़ाइलें Bazel के अलावा किसी अन्य इकाई को उपलब्ध करानी हैं, तो Bazel --distdir
विकल्प का इस्तेमाल किया जा सकता है. जब भी कोई रिपॉज़िटरी नियम, Bazel को ctx.download
या ctx.download_and_extract
के ज़रिए कोई फ़ाइल फ़ेच करने के लिए कहता है और ज़रूरी फ़ाइल का हैश सम देता है, तो Bazel सबसे पहले उस विकल्प के ज़रिए बताई गई डायरेक्ट्री में, दिए गए पहले यूआरएल के बेसनेम से मेल खाने वाली फ़ाइल को खोजेगा. अगर हैश मेल खाता है, तो Bazel उस लोकल कॉपी का इस्तेमाल करेगा.
Bazel खुद इस तकनीक का इस्तेमाल करके, डिस्ट्रिब्यूशन आर्टफ़ैक्ट से ऑफ़लाइन बूटस्ट्रैप करता है.
यह ऐसा, सभी ज़रूरी बाहरी डिपेंडेंसी को इकट्ठा करके करता है. इसके बाद, इन्हें एक इंटरनल distdir_tar
में शामिल करता है.
हालांकि, Bazel, रिपॉज़िटरी के नियमों में किसी भी कमांड को चलाने की अनुमति देता है. इससे यह पता नहीं चलता कि वे नेटवर्क को कॉल करते हैं या नहीं. इसलिए, Bazel के पास यह विकल्प नहीं है कि वह बिल्ड को पूरी तरह से ऑफ़लाइन होने के लिए मजबूर करे. इसलिए, यह जांचने के लिए कि कोई बिल्ड ऑफ़लाइन मोड में सही तरीके से काम करता है या नहीं, नेटवर्क को बाहरी तौर पर ब्लॉक करना ज़रूरी है. ऐसा Bazel अपने बूटस्ट्रैप टेस्ट में करता है.
सबसे सही तरीके
रिपॉज़िटरी के नियम
आम तौर पर, रिपॉज़िटरी के नियम में ये बातें शामिल होनी चाहिए:
- सिस्टम की सेटिंग का पता लगाना और उन्हें फ़ाइलों में लिखना.
- सिस्टम पर मौजूद अन्य संसाधनों को ढूंढना.
- यूआरएल से संसाधन डाउनलोड किए जा रहे हैं.
- बाहरी रिपॉज़िटरी डायरेक्ट्री में BUILD फ़ाइलें जनरेट करना या सिमलंक करना.
अगर हो सके, तो repository_ctx.execute
का इस्तेमाल न करें. उदाहरण के लिए, अगर आपको Make का इस्तेमाल करके बनाई गई Bazel के अलावा किसी अन्य C++ लाइब्रेरी का इस्तेमाल करना है, तो repository_ctx.download()
चलाने के बजाय, repository_ctx.download()
का इस्तेमाल करना बेहतर होता है. इसके बाद, एक BUILD फ़ाइल लिखें, जो इसे बनाए.ctx.execute(["make"])
git_repository
और new_git_repository
के बजाय, http_archive
को प्राथमिकता दें. इसकी वजहें ये हैं:
- Git रिपॉज़िटरी के नियम, सिस्टम
git(1)
पर निर्भर करते हैं. वहीं, एचटीटीपी डाउनलोडर को Bazel में बनाया गया है और इसकी कोई सिस्टम डिपेंडेंसी नहीं है. http_archive
,urls
की सूची को मिरर के तौर पर इस्तेमाल करता है. वहीं,git_repository
सिर्फ़ एकremote
के साथ काम करता है.http_archive
, रिपॉज़िटरी कैश मेमोरी के साथ काम करता है, लेकिनgit_repository
के साथ नहीं. ज़्यादा जानकारी के लिए, #5116 देखें.
bind()
का इस्तेमाल न करें. इसकी समस्याओं और विकल्पों के बारे में ज़्यादा जानकारी के लिए, "बाइंड हटाने पर विचार करें" लेख पढ़ें.