इस पेज पर, Bazel के दो विज़िबिलिटी सिस्टम के बारे में बताया गया है: टारगेट विज़िबिलिटी और लोड विज़िबिलिटी.
दोनों तरह की विज़िबिलिटी से, अन्य डेवलपर को आपकी लाइब्रेरी के सार्वजनिक एपीआई और उसके लागू करने की जानकारी के बीच अंतर करने में मदद मिलती है. साथ ही, इससे आपके वर्कस्पेस के बढ़ने पर स्ट्रक्चर को लागू करने में मदद मिलती है. सार्वजनिक एपीआई को बंद करते समय भी, इस सेटिंग का इस्तेमाल किया जा सकता है. इससे मौजूदा उपयोगकर्ताओं को एपीआई का इस्तेमाल करने की अनुमति दी जा सकती है, जबकि नए उपयोगकर्ताओं को अनुमति नहीं दी जा सकती.
टारगेट किसको दिखे
टारगेट दिखने की सेटिंग से यह कंट्रोल किया जाता है कि कौन आपके टारगेट पर निर्भर हो सकता है. इसका मतलब है कि कौन deps जैसे एट्रिब्यूट में आपके टारगेट के लेबल का इस्तेमाल कर सकता है.
अगर टारगेट A और टारगेट B एक ही पैकेज में हैं या A, B के पैकेज को दिखने की अनुमति देता है, तो टारगेट A, टारगेट B को दिखता है. इसलिए, पैकेज के आधार पर यह तय किया जाता है कि ऐक्सेस की अनुमति देनी है या नहीं. अगर B, A पर निर्भर करता है, लेकिन A, B को नहीं दिखता है, तो विश्लेषण के दौरान B बनाने की कोई भी कोशिश पूरी नहीं होती.
ध्यान दें कि किसी पैकेज को दिखने की अनुमति देने से, उसके सब-पैकेज को दिखने की अनुमति अपने-आप नहीं मिल जाती. पैकेज और सब-पैकेज के बारे में ज़्यादा जानने के लिए, कॉन्सेप्ट और शब्दावली देखें.
प्रोटोटाइपिंग के लिए, टारगेट दिखने की सुविधा को लागू करने की सुविधा बंद की जा सकती है. इसके लिए, --check_visibility=false फ़्लैग सेट करें. सबमिट किए गए कोड में, प्रोडक्शन के लिए इसका इस्तेमाल नहीं किया जाना चाहिए.
किसी आइटम के दिखने या न दिखने की सेटिंग को कंट्रोल करने का मुख्य तरीका, नियम के टारगेट पर visibility एट्रिब्यूट का इस्तेमाल करना है. इस सेक्शन में, इस एट्रिब्यूट के फ़ॉर्मैट के बारे में बताया गया है. साथ ही, यह भी बताया गया है कि टारगेट की विज़िबिलिटी का पता कैसे लगाया जाता है.
प्रॉडक्ट के दिखने से जुड़ी खास जानकारी
नियम के सभी टारगेट में एक visibility एट्रिब्यूट होता है. यह एट्रिब्यूट, लेबल की सूची लेता है. हर लेबल, इनमें से किसी एक फ़ॉर्म में होता है. आखिरी फ़ॉर्म को छोड़कर, ये सिर्फ़ सिंटैक्टिक प्लेसहोल्डर हैं. इनका किसी भी असल टारगेट से कोई लेना-देना नहीं है.
"//visibility:public": इससे सभी पैकेज का ऐक्सेस मिलता है. (इसे किसी अन्य स्पेसिफ़िकेशन के साथ इस्तेमाल नहीं किया जा सकता.)"//visibility:private": इससे कोई अतिरिक्त ऐक्सेस नहीं मिलता है. सिर्फ़ इस पैकेज में मौजूद टारगेट, इस टारगेट का इस्तेमाल कर सकते हैं. (इसे किसी अन्य स्पेसिफ़िकेशन के साथ नहीं जोड़ा जा सकता.)"//foo/bar:__pkg__"://foo/barको ऐक्सेस देता है, लेकिन इसके सबपैकेज को नहीं."//foo/bar:__subpackages__": यह//foo/barऔर इसके सभी डायरेक्ट और इनडायरेक्ट सब-पैकेज को ऐक्सेस करने की अनुमति देता है."//some_pkg:my_package_group": इससे उन सभी पैकेज का ऐक्सेस मिलता है जो दिए गएpackage_groupका हिस्सा हैं.- पैकेज ग्रुप में, पैकेज तय करने के लिए अलग सिंटैक्स का इस्तेमाल किया जाता है. पैकेज ग्रुप में, फ़ॉर्म
"//foo/bar:__pkg__"और"//foo/bar:__subpackages__"को क्रमशः"//foo/bar"और"//foo/bar/..."से बदल दिया जाता है. इसी तरह,"//visibility:public"और"//visibility:private"सिर्फ़"public"और"private"हैं.
- पैकेज ग्रुप में, पैकेज तय करने के लिए अलग सिंटैक्स का इस्तेमाल किया जाता है. पैकेज ग्रुप में, फ़ॉर्म
उदाहरण के लिए, अगर //some/package:mytarget का visibility, [":__subpackages__", "//tests:__pkg__"] पर सेट है, तो इसका इस्तेमाल //some/package/... सोर्स ट्री में शामिल किसी भी टारगेट के साथ-साथ //tests/BUILD में तय किए गए टारगेट के लिए किया जा सकता है. हालांकि, इसका इस्तेमाल //tests/integration/BUILD में तय किए गए टारगेट के लिए नहीं किया जा सकता.
सबसे सही तरीका: अगर आपको एक ही सेट के कई टारगेट को पैकेज के एक ही सेट के लिए दिखाना है, तो हर टारगेट के visibility एट्रिब्यूट में सूची को दोहराने के बजाय, package_group का इस्तेमाल करें. इससे सूची को पढ़ना आसान हो जाता है और सूचियों के सिंक न होने की समस्या नहीं होती.
नियम के टारगेट की विज़िबिलिटी
किसी नियम के टारगेट की विज़िबिलिटी:
अगर
visibilityएट्रिब्यूट की वैल्यू सेट की गई है, तो वह वैल्यू; याअगर टारगेट की
BUILDफ़ाइल में ऐसा एलान मौजूद है, तोpackageस्टेटमेंट केdefault_visibilityतर्क की वैल्यू; या//visibility:private.
सबसे सही तरीका: default_visibility को सार्वजनिक के तौर पर सेट न करें. यह प्रोटोटाइपिंग या छोटे कोडबेस के लिए सुविधाजनक हो सकता है. हालांकि, कोडबेस के बढ़ने पर, गलती से सार्वजनिक टारगेट बनाने का जोखिम बढ़ जाता है. यह बेहतर है कि आप साफ़ तौर पर बताएं कि पैकेज के सार्वजनिक इंटरफ़ेस में कौनसे टारगेट शामिल हैं.
उदाहरण
फ़ाइल //frobber/bin/BUILD:
# This target is visible to everyone
cc_binary(
name = "executable",
visibility = ["//visibility:public"],
deps = [":library"],
)
# This target is visible only to targets declared in the same package
cc_library(
name = "library",
# No visibility -- defaults to private since no
# package(default_visibility = ...) was used.
)
# This target is visible to targets in package //object and //noun
cc_library(
name = "subject",
visibility = [
"//noun:__pkg__",
"//object:__pkg__",
],
)
# See package group "//frobber:friends" (below) for who can
# access this target.
cc_library(
name = "thingy",
visibility = ["//frobber:friends"],
)
फ़ाइल //frobber/BUILD:
# This is the package group declaration to which target
# //frobber/bin:thingy refers.
#
# Our friends are packages //frobber, //fribber and any
# subpackage of //fribber.
package_group(
name = "friends",
packages = [
"//fribber/...",
"//frobber",
],
)
जनरेट की गई फ़ाइल के लिए टारगेट विज़िबिलिटी
जनरेट की गई फ़ाइल के टारगेट की विज़िबिलिटी, उस नियम के टारगेट के बराबर होती है जो उसे जनरेट करता है.
सोर्स फ़ाइल का टारगेट किसको दिखेगा
exports_files को कॉल करके, सोर्स फ़ाइल के टारगेट की विज़िबिलिटी को साफ़ तौर पर सेट किया जा सकता है. exports_files को कोई visibility
आर्ग्युमेंट न देने पर, विज़िबिलिटी को सार्वजनिक कर दिया जाता है.
जनरेट की गई फ़ाइल की दृश्यता को बदलने के लिए, exports_files का इस्तेमाल नहीं किया जा सकता.
जिन सोर्स फ़ाइल टारगेट के लिए exports_files को कॉल नहीं किया जाता है उनके लिए, दिखने की सेटिंग इस फ़्लैग की वैल्यू पर निर्भर करती है: --incompatible_no_implicit_file_export:
अगर फ़्लैग सेट है, तो वीडियो को 'निजी' के तौर पर सेट किया जाता है.
इसके अलावा, लेगसी वर्शन में मौजूद सुविधा काम करती है: वीडियो के दिखने की सेटिंग वही होती है जो
BUILDफ़ाइलdefault_visibilityके लिए सेट की गई है. अगर डिफ़ॉल्ट रूप से वीडियो के दिखने की सेटिंग नहीं चुनी गई है, तो वीडियो के दिखने की सेटिंग 'निजी' पर सेट होती है.
लेगसी वर्शन के व्यवहार पर भरोसा न करें. जब भी किसी सोर्स फ़ाइल के टारगेट को गैर-निजी तौर पर दिखाना हो, तब हमेशा exports_files
डिक्लेरेशन लिखें.
सबसे सही तरीका: जब भी मुमकिन हो, सोर्स फ़ाइल के बजाय नियम के टारगेट को दिखाएं. उदाहरण के लिए, किसी .java फ़ाइल पर exports_files कॉल करने के बजाय, फ़ाइल को गैर-निजी java_library टारगेट में रैप करें. आम तौर पर, नियम के टारगेट को सिर्फ़ उन सोर्स फ़ाइलों को सीधे तौर पर रेफ़रंस करना चाहिए जो एक ही पैकेज में मौजूद हैं.
उदाहरण
फ़ाइल //frobber/data/BUILD:
exports_files(["readme.txt"])
फ़ाइल //frobber/bin/BUILD:
cc_binary(
name = "my-program",
data = ["//frobber/data:readme.txt"],
)
कॉन्फ़िगरेशन सेटिंग की विज़िबिलिटी
पहले, Bazel ने select() की कुंजियों में रेफ़र किए गए config_setting टारगेट के लिए, विज़िबिलिटी लागू नहीं की थी. लेगसी वर्शन के इस व्यवहार को हटाने के लिए, दो फ़्लैग उपलब्ध हैं:
--incompatible_enforce_config_setting_visibilityइन टारगेट के लिए, दिखने की स्थिति की जांच करने की सुविधा चालू करता है. माइग्रेशन में मदद करने के लिए, यह उन सभीconfig_settingको भी सार्वजनिक तौर पर उपलब्ध कराता है जिनमेंvisibilityके बारे में नहीं बताया गया है. भले ही, पैकेज-लेवलdefault_visibilityकुछ भी हो.--incompatible_config_setting_private_default_visibilityconfig_settingकी वजह से,visibilityके बारे में नहीं बताया जाता है. इससे पैकेज केdefault_visibilityका पालन किया जाता है और निजता सेटिंग को डिफ़ॉल्ट रूप से लागू किया जाता है. यह किसी अन्य नियम के टारगेट की तरह ही होता है. अगर--incompatible_enforce_config_setting_visibilityसेट नहीं है, तो यह विकल्प काम नहीं करता.
लेगसी वर्शन के व्यवहार पर भरोसा न करें. अगर किसी config_setting का इस्तेमाल मौजूदा पैकेज के बाहर किया जाना है, तो उसके लिए visibility की वैल्यू साफ़ तौर पर दी जानी चाहिए. ऐसा तब करना चाहिए, जब पैकेज में पहले से कोई सही default_visibility वैल्यू न दी गई हो.
पैकेज ग्रुप के टारगेट को दिखाने की सुविधा
package_group टारगेट में visibility एट्रिब्यूट नहीं है. ये हमेशा सार्वजनिक तौर पर दिखते हैं.
इंप्लिसिट डिपेंडेंसी का दिखना
कुछ नियमों में इंप्लिसिट डिपेंडेंसी होती हैं. ये ऐसी डिपेंडेंसी होती हैं जिनके बारे में BUILD फ़ाइल में नहीं बताया जाता, लेकिन वे उस नियम के हर इंस्टेंस के लिए ज़रूरी होती हैं. उदाहरण के लिए, cc_library नियम, अपने हर नियम टारगेट से C++ कंपाइलर को दिखाने वाले एक्ज़ीक्यूटेबल टारगेट तक एक इंप्लिसिट डिपेंडेंसी बना सकता है.
इस तरह की इंप्लिसिट डिपेंडेंसी की विज़िबिलिटी की जांच, उस पैकेज के हिसाब से की जाती है जिसमें .bzl फ़ाइल मौजूद होती है. इस फ़ाइल में नियम (या पहलू) तय किया जाता है. हमारे उदाहरण में, C++ कंपाइलर को तब तक निजी रखा जा सकता है, जब तक वह cc_library नियम की परिभाषा वाले पैकेज में मौजूद है. अगर परिभाषा में साफ़ तौर पर नहीं बताया गया है कि कोई डिपेंडेंसी मौजूद है, तो फ़ॉलबैक के तौर पर cc_library टारगेट के हिसाब से इसकी जांच की जाती है.
--incompatible_visibility_private_attributes_at_definition को बंद करके, इस सुविधा को बदला जा सकता है.
इस सुविधा के बंद होने पर, इंप्लिसिट डिपेंडेंसी को किसी अन्य डिपेंडेंसी की तरह माना जाता है.
इसका मतलब है कि जिस टारगेट पर निर्भरता है (जैसे कि हमारा C++ कंपाइलर) वह नियम के हर इंस्टेंस को दिखना चाहिए. आम तौर पर, इसका मतलब है कि टारगेट को सार्वजनिक तौर पर दिखना चाहिए.
अगर आपको किसी नियम का इस्तेमाल सिर्फ़ कुछ पैकेज के लिए करना है, तो इसके बजाय लोड दिखने की सुविधा का इस्तेमाल करें.
लोड होने की स्थिति
लोड करने की सुविधा से यह कंट्रोल किया जाता है कि किसी .bzl फ़ाइल को अन्य BUILD या .bzl फ़ाइलों से लोड किया जा सकता है या नहीं.
जिस तरह टारगेट विज़िबिलिटी, टारगेट में शामिल सोर्स कोड की सुरक्षा करती है उसी तरह लोड विज़िबिलिटी, .bzl फ़ाइलों में शामिल बिल्ड लॉजिक की सुरक्षा करती है. उदाहरण के लिए, ऐसा हो सकता है कि BUILD फ़ाइल का लेखक, बार-बार इस्तेमाल होने वाली कुछ टारगेट डेफ़िनिशन को .bzl फ़ाइल में मौजूद मैक्रो में शामिल करना चाहे. लोड विज़िबिलिटी की सुरक्षा के बिना, उन्हें पता चल सकता है कि उनके मैक्रो का इस्तेमाल एक ही वर्कस्पेस में मौजूद अन्य सहयोगियों ने किया है. इससे मैक्रो में बदलाव करने पर, अन्य टीमों के बिल्ड में गड़बड़ी हो सकती है.
ध्यान दें कि किसी .bzl फ़ाइल में, उससे जुड़ी सोर्स फ़ाइल का टारगेट हो भी सकता है और नहीं भी.
ऐसा होने पर भी, इस बात की कोई गारंटी नहीं है कि लोड विज़िबिलिटी और टारगेट विज़िबिलिटी एक जैसी होगी. इसका मतलब है कि एक ही BUILD फ़ाइल, .bzl फ़ाइल को लोड कर सकती है, लेकिन उसे filegroup के srcs में नहीं दिखा सकती. इसके उलट भी हो सकता है. कभी-कभी, इससे उन नियमों के लिए समस्याएं हो सकती हैं जो .bzl फ़ाइलों को सोर्स कोड के तौर पर इस्तेमाल करना चाहते हैं. जैसे, दस्तावेज़ जनरेट करने या टेस्टिंग के लिए.
प्रोटोटाइपिंग के लिए, --check_bzl_visibility=false सेट करके, लोड विज़िबिलिटी लागू करने की सुविधा बंद की जा सकती है. --check_visibility=false की तरह, सबमिट किए गए कोड के लिए ऐसा नहीं किया जाना चाहिए.
लोड विज़िबिलिटी की सुविधा, Bazel 6.0 से उपलब्ध है.
लोड दिखने की स्थिति के बारे में जानकारी देना
.bzl फ़ाइल के लोड होने की स्थिति सेट करने के लिए, फ़ाइल में मौजूद visibility() फ़ंक्शन को कॉल करें.
visibility() का तर्क, पैकेज की खास जानकारी की सूची होती है. यह package_group के packages एट्रिब्यूट की तरह ही होता है. हालांकि, visibility() नेगेटिव पैकेज स्पेसिफ़िकेशन स्वीकार नहीं करता.
visibility() को हर फ़ाइल में सिर्फ़ एक बार कॉल किया जाना चाहिए. इसे टॉप लेवल पर (किसी फ़ंक्शन के अंदर नहीं) कॉल किया जाना चाहिए. साथ ही, इसे load() स्टेटमेंट के तुरंत बाद कॉल किया जाना चाहिए.
टारगेट किए गए लोगों को दिखने की सुविधा के उलट, डिफ़ॉल्ट रूप से लोड होने वाले विज्ञापन हमेशा सार्वजनिक होते हैं. visibility() को कॉल नहीं करने वाली फ़ाइलों को वर्कस्पेस में कहीं से भी लोड किया जा सकता है. यह सुझाव दिया जाता है कि आप किसी भी नई .bzl फ़ाइल के सबसे ऊपर visibility("private") जोड़ें. हालांकि, यह सिर्फ़ उन फ़ाइलों के लिए है जिनका इस्तेमाल पैकेज के बाहर नहीं किया जाना है.
उदाहरण
# //mylib/internal_defs.bzl
# Available to subpackages and to mylib's tests.
visibility(["//mylib/...", "//tests/mylib/..."])
def helper(...):
...
# //mylib/rules.bzl
load(":internal_defs.bzl", "helper")
# Set visibility explicitly, even though public is the default.
# Note the [] can be omitted when there's only one entry.
visibility("public")
myrule = rule(
...
)
# //someclient/BUILD
load("//mylib:rules.bzl", "myrule") # ok
load("//mylib:internal_defs.bzl", "helper") # error
...
विज्ञापन दिखने की दर को बेहतर बनाने के तरीके
इस सेक्शन में, लोड दिखने की सेटिंग के बारे में जानकारी देने से जुड़े सुझाव दिए गए हैं.
फ़ैक्टराइज़ेशन की मदद से विज़िबिलिटी तय करना
जब कई .bzl फ़ाइलों को एक ही तरह से दिखाया जाना हो, तो उनके पैकेज की खास बातों को एक ही सूची में शामिल करना मददगार हो सकता है. उदाहरण के लिए:
# //mylib/internal_defs.bzl
visibility("private")
clients = [
"//foo",
"//bar/baz/...",
...
]
# //mylib/feature_A.bzl
load(":internal_defs.bzl", "clients")
visibility(clients)
...
# //mylib/feature_B.bzl
load(":internal_defs.bzl", "clients")
visibility(clients)
...
इससे अलग-अलग .bzl फ़ाइलों के दिखने की संभावना में अनजाने में होने वाली गड़बड़ी को रोकने में मदद मिलती है. clients सूची बड़ी होने पर, इसे पढ़ना भी आसान होता है.
लिखते समय दिखने वाली चीज़ें
कभी-कभी, .bzl फ़ाइल को ऐसी अनुमति वाली सूची में दिखना चाहिए जिसमें कई छोटी-छोटी अनुमति वाली सूचियां शामिल हों. यह इस तरह काम करता है कि includes एट्रिब्यूट के ज़रिए, कोई package_group अन्य package_group को शामिल कर सकता है.
मान लें कि आपको किसी ऐसे मैक्रो को बंद करना है जिसका इस्तेमाल बड़े पैमाने पर किया जाता है. आपको इसे सिर्फ़ मौजूदा उपयोगकर्ताओं और आपकी टीम के मालिकाना हक वाले पैकेज के लिए दिखाना है. कुछ ऐसा लिखा जा सकता है:
# //mylib/macros.bzl
load(":internal_defs.bzl", "our_packages")
load("//some_big_client:defs.bzl", "their_remaining_uses)
# List concatenation. Duplicates are fine.
visibility(our_packages + their_remaining_uses)
पैकेज ग्रुप की मदद से डुप्लीकेट आइटम हटाना
टारगेट विज़िबिलिटी के उलट, लोड विज़िबिलिटी को package_group के हिसाब से तय नहीं किया जा सकता. अगर आपको टारगेट करने की सुविधा और लोड करने की सुविधा, दोनों के लिए एक ही अनुमति वाली सूची का फिर से इस्तेमाल करना है, तो पैकेज के स्पेसिफ़िकेशन की सूची को .bzl फ़ाइल में ले जाना सबसे अच्छा है. इससे दोनों तरह के एलान, इस सूची का इस्तेमाल कर सकते हैं. ऊपर दिखने की स्थितियां में दिए गए उदाहरण के आधार पर, यह लिखा जा सकता है:
# //mylib/BUILD
load(":internal_defs", "clients")
package_group(
name = "my_pkg_grp",
packages = clients,
)
यह सुविधा सिर्फ़ तब काम करती है, जब सूची में कोई नेगेटिव पैकेज स्पेसिफ़िकेशन शामिल न हो.
अलग-अलग सिंबल को सुरक्षित रखना
जिस Starlark सिंबल का नाम अंडरस्कोर से शुरू होता है उसे किसी दूसरी फ़ाइल से लोड नहीं किया जा सकता. इससे निजी सिंबल आसानी से बनाए जा सकते हैं. हालांकि, इससे इन सिंबल को भरोसेमंद फ़ाइलों के सीमित सेट के साथ शेयर नहीं किया जा सकता. दूसरी ओर, लोड विज़िबिलिटी से यह कंट्रोल किया जा सकता है कि अन्य पैकेज आपके .bzl file को देख सकते हैं या नहीं. हालांकि, इससे आपको किसी भी ऐसे सिंबल को लोड होने से रोकने की अनुमति नहीं मिलती है जिसमें अंडरस्कोर नहीं है.
अच्छी बात यह है कि इन दोनों सुविधाओं को एक साथ इस्तेमाल किया जा सकता है, ताकि आपको बेहतर कंट्रोल मिल सके.
# //mylib/internal_defs.bzl
# Can't be public, because internal_helper shouldn't be exposed to the world.
visibility("private")
# Can't be underscore-prefixed, because this is
# needed by other .bzl files in mylib.
def internal_helper(...):
...
def public_util(...):
...
# //mylib/defs.bzl
load(":internal_defs", "internal_helper", _public_util="public_util")
visibility("public")
# internal_helper, as a loaded symbol, is available for use in this file but
# can't be imported by clients who load this file.
...
# Re-export public_util from this file by assigning it to a global variable.
# We needed to import it under a different name ("_public_util") in order for
# this assignment to be legal.
public_util = _public_util
bzl-visibility Buildifier lint
Buildifier lint मौजूद है. यह उपयोगकर्ताओं को चेतावनी देता है, अगर वे internal या private नाम की किसी डायरेक्ट्री से कोई फ़ाइल लोड करते हैं. ऐसा तब होता है, जब उपयोगकर्ता की फ़ाइल उस डायरेक्ट्री के पैरंट डायरेक्ट्री में मौजूद न हो. यह लिंट, लोड विज़िबिलिटी की सुविधा से पहले का है. साथ ही, यह उन वर्कस्पेस में ज़रूरी नहीं है जहां .bzl फ़ाइलें विज़िबिलिटी तय करती हैं.