इस पेज पर, Bazel के विज़िबिलिटी सिस्टम के बारे में बताया गया है: टारगेट विज़िबिलिटी और लोड विज़िबिलिटी.
विज़िबिलिटी से जुड़ी दोनों सेटिंग से अन्य डेवलपर को आपकी लाइब्रेरी के सार्वजनिक एपीआई और उसे लागू करने से जुड़ी जानकारी के बीच अंतर करने में मदद मिलती है. साथ ही, आपका फ़ाइल फ़ोल्डर बढ़ता है. इससे स्ट्रक्चर को लागू करने में भी मदद मिलती है. किसी सार्वजनिक एपीआई को बंद करते समय, 'दिखाई जा रही है' एट्रिब्यूट का इस्तेमाल करके, मौजूदा उपयोगकर्ताओं को अनुमति दी जा सकती है और नए उपयोगकर्ताओं को अनुमति नहीं दी जा सकती.
टारगेट किसको दिखे
टारगेट की दिखने की सेटिंग से यह कंट्रोल होता है कि आपके टारगेट पर कौन निर्भर हो सकता है. इसका मतलब है कि deps
जैसे किसी एट्रिब्यूट में, आपके टारगेट के लेबल का इस्तेमाल कौन कर सकता है.
टारगेट 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
को सार्वजनिक माना जाता है. भले ही, पैकेज-लेवलdefault_visibility
कुछ भी हो. ऐसा तब भी होता है, जबconfig_setting
मेंvisibility
की जानकारी न दी गई हो.--incompatible_config_setting_private_default_visibility
की वजह सेconfig_setting
होते हैं, जो पैकेज केdefault_visibility
के हिसाब से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
में शामिल नहीं कर सकती. इसके अलावा, ऐसा भी हो सकता है कि 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
फ़ाइल, अनुमति वाली सूची में दिखे, जिसमें कई छोटी-छोटी फ़ाइलें शामिल हों. यह उसी तरह है जिस तरह कोई package_group
, अपने includes
एट्रिब्यूट की मदद से अन्य 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-विज़िबिलिटी बिल्डिफ़ायर लिंट
एक बिल्डिफ़ायर लिंट होता है, जो उस स्थिति में चेतावनी देता है, जब उपयोगकर्ता internal
या private
नाम की डायरेक्ट्री से कोई फ़ाइल लोड करते हैं. ऐसा तब होता है, जब उपयोगकर्ता की फ़ाइल उस डायरेक्ट्री के पैरंट के नीचे मौजूद न हो. यह लिंट, लोड होने की जानकारी दिखाने की सुविधा से पहले का है. साथ ही, यह उन फ़ाइल फ़ोल्डर में गैर-ज़रूरी है जहां .bzl
फ़ाइलें, दिखने की सेटिंग के बारे में बताती हैं.