इस पेज पर, Bazel के तीन विज़िबिलिटी सिस्टम के बारे में बताया गया है: टारगेट विज़िबिलिटी, ट्रांज़िटिव विज़िबिलिटी और लोड विज़िबिलिटी.
विज़िबिलिटी के इन टाइप से, अन्य डेवलपर को आपकी लाइब्रेरी के सार्वजनिक एपीआई और उसके लागू करने से जुड़ी जानकारी के बीच अंतर करने में मदद मिलती है. साथ ही, आपका वर्कस्पेस बढ़ने पर, स्ट्रक्चर को लागू करने में मदद मिलती है. सार्वजनिक एपीआई को बंद करते समय, विज़िबिलिटी का इस्तेमाल किया जा सकता है. इससे मौजूदा उपयोगकर्ताओं को एपीआई का ऐक्सेस दिया जा सकता है, जबकि नए उपयोगकर्ताओं को ऐक्सेस नहीं दिया जा सकता.
टारगेट विज़िबिलिटी
टारगेट विज़िबिलिटी से यह कंट्रोल किया जाता है कि आपके टारगेट पर कौन निर्भर हो सकता है. इसका मतलब है कि deps जैसे एट्रिब्यूट में, आपके टारगेट के लेबल का इस्तेमाल कौन कर सकता है. अगर कोई टारगेट, अपनी किसी डिपेंडेंसी की विज़िबिलिटी का उल्लंघन करता है, तो विश्लेषण के दौरान उसे बनाया नहीं जा सकेगा.
आम तौर पर, टारगेट A, टारगेट B को तब दिखता है, जब दोनों एक ही जगह पर हों या जब A, 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 का इस्तेमाल करें. इससे सूची को पढ़ना आसान हो जाता है और सूची के सिंक से बाहर होने की समस्या से बचा जा सकता है.
सबसे सही तरीका: किसी दूसरी टीम के प्रोजेक्ट को विज़िबिलिटी की अनुमति देते समय, __pkg__ के बजाय __subpackages__ का इस्तेमाल करें. इससे प्रोजेक्ट के बढ़ने और नए सब-पैकेज जोड़ने पर, विज़िबिलिटी में होने वाले गैर-ज़रूरी बदलावों से बचा जा सकता है.
नियम के टारगेट की विज़िबिलिटी
नियम के टारगेट की विज़िबिलिटी, उसके visibility एट्रिब्यूट
या डिफ़ॉल्ट विज़िबिलिटी (अगर कोई एट्रिब्यूट नहीं दिया गया है) के हिसाब से तय की जाती है. इसके साथ, टारगेट तय करने की जगह भी जोड़ी जाती है. सिंबॉलिक मैक्रो में तय नहीं किए गए टारगेट के लिए, अगर
पैकेज में default_visibility तय की गई है, तो
इस डिफ़ॉल्ट विज़िबिलिटी का इस्तेमाल किया जाता है. अन्य सभी पैकेज और
सिंबॉलिक मैक्रो में तय किए गए टारगेट के लिए, डिफ़ॉल्ट विज़िबिलिटी सिर्फ़ ["//visibility:private"] होती है.
# //mypkg/BUILD
package(default_visibility = ["//friend:__pkg__"])
cc_library(
name = "t1",
...
# No visibility explicitly specified.
# Effective visibility is ["//friend:__pkg__", "//mypkg:__pkg__"].
# If no default_visibility were given in package(...), the visibility would
# instead default to ["//visibility:private"], and the effective visibility
# would be ["//mypkg:__pkg__"].
)
cc_library(
name = "t2",
...
visibility = [":clients"],
# Effective visibility is ["//mypkg:clients, "//mypkg:__pkg__"], which will
# expand to ["//another_friend:__subpackages__", "//mypkg:__pkg__"].
)
cc_library(
name = "t3",
...
visibility = ["//visibility:private"],
# Effective visibility is ["//mypkg:__pkg__"]
)
package_group(
name = "clients",
packages = ["//another_friend/..."],
)
सबसे सही तरीका: default_visibility को सार्वजनिक पर सेट करने से बचें. प्रोटोटाइप बनाने या छोटे कोडबेस में यह सुविधाजनक हो सकता है. हालांकि, कोडबेस बढ़ने पर, गलती से सार्वजनिक टारगेट बनाने का खतरा बढ़ जाता है. यह बताना बेहतर है कि कौनसे टारगेट, किसी पैकेज के सार्वजनिक इंटरफ़ेस का हिस्सा हैं.
जनरेट की गई फ़ाइल के टारगेट की विज़िबिलिटी
जनरेट की गई फ़ाइल के टारगेट की विज़िबिलिटी, उसे जनरेट करने वाले नियम के टारगेट की विज़िबिलिटी के बराबर होती है.
# //mypkg/BUILD
java_binary(
name = "foo",
...
visibility = ["//friend:__pkg__"],
)
# //friend/BUILD
some_rule(
name = "bar",
deps = [
# Allowed directly by visibility of foo.
"//mypkg:foo",
# Also allowed. The java_binary's "_deploy.jar" implicit output file
# target the same visibility as the rule target itself.
"//mypkg:foo_deploy.jar",
]
...
)
सोर्स फ़ाइल के टारगेट की विज़िबिलिटी
सोर्स फ़ाइल के टारगेट को,
exports_files का इस्तेमाल करके साफ़ तौर पर तय किया जा सकता है. इसके अलावा, किसी नियम के लेबल एट्रिब्यूट (सिंबॉलिक मैक्रो के बाहर) में, उसके फ़ाइल नाम को रेफ़र करके भी सोर्स फ़ाइल के टारगेट को तय किया जा सकता है. नियम के टारगेट की तरह, exports_files को कॉल करने की जगह या इनपुट फ़ाइल को रेफ़र करने वाली BUILD फ़ाइल, हमेशा फ़ाइल की विज़िबिलिटी में अपने-आप जुड़ जाती है.
exports_files से तय की गई फ़ाइलों की विज़िबिलिटी, उस फ़ंक्शन के visibility पैरामीटर से सेट की जा सकती है. अगर यह पैरामीटर नहीं दिया जाता है, तो विज़िबिलिटी सार्वजनिक होती है.
जिन फ़ाइलों के लिए 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,
config_setting टारगेट के लिए विज़िबिलिटी लागू नहीं करता था. इन टारगेट को
select() की कुंजियों में रेफ़र किया जाता था. इस पुराने तरीके को हटाने के लिए, दो फ़्लैग उपलब्ध हैं:
--incompatible_enforce_config_setting_visibilityसे, इन टारगेट के लिए विज़िबिलिटी की जांच की जा सकती है. माइग्रेशन में मदद करने के लिए, इससे ऐसे सभीconfig_settingको सार्वजनिक माना जाता है जिनमेंvisibilityतय नहीं की गई है. भले ही, पैकेज-लेवल परdefault_visibilityकुछ भी हो.--incompatible_config_setting_private_default_visibilityसे, ऐसेconfig_settingको पैकेज कीdefault_visibilityके हिसाब से सेट किया जाता है जिनमेंvisibilityतय नहीं की गई है. साथ ही, किसी अन्य नियम के टारगेट की तरह, डिफ़ॉल्ट विज़िबिलिटी के तौर पर निजी विज़िबिलिटी का इस्तेमाल किया जाता है. अगर--incompatible_enforce_config_setting_visibilityसेट नहीं है, तो इसका कोई असर नहीं होता.
पुराने तरीके पर निर्भर रहने से बचें. अगर पैकेज में, default_visibility तय नहीं की गई है, तो मौजूदा पैकेज के बाहर इस्तेमाल किए जाने वाले किसी भी config_setting के लिए, visibility साफ़ तौर पर तय की जानी चाहिए.
पैकेज ग्रुप के टारगेट की विज़िबिलिटी
package_group टारगेट में, visibility एट्रिब्यूट नहीं होता. ये हमेशा सार्वजनिक तौर पर दिखते हैं.
इंप्लिसिट डिपेंडेंसी की विज़िबिलिटी
कुछ नियमों में इंप्लिसिट डिपेंडेंसी होती हैं. ये ऐसी
डिपेंडेंसी होती हैं जिन्हें BUILD फ़ाइल में साफ़ तौर पर नहीं बताया जाता, लेकिन ये उस नियम के
हर इंस्टेंस में मौजूद होती हैं. उदाहरण के लिए, cc_library नियम, अपने हर नियम के टारगेट से, C++ कंपाइलर को दिखाने वाले एक्ज़ीक्यूटेबल टारगेट के लिए, इंप्लिसिट डिपेंडेंसी बना सकता है.
ऐसी इंप्लिसिट डिपेंडेंसी की विज़िबिलिटी की जांच, उस पैकेज के हिसाब से की जाती है जिसमें .bzl फ़ाइल मौजूद है. इस फ़ाइल में, नियम (या आसपेक्ट) तय किया जाता है. हमारे उदाहरण में, C++ कंपाइलर को निजी बनाया जा सकता है, बशर्ते वह cc_library नियम की परिभाषा वाले पैकेज में ही मौजूद हो. अगर इंप्लिसिट डिपेंडेंसी, परिभाषा से नहीं दिखती है, तो इसकी जांच cc_library टारगेट के हिसाब से की जाती है.
अगर आपको किसी नियम के इस्तेमाल को कुछ पैकेज तक सीमित करना है, तो इसके बजाय लोड विज़िबिलिटी का इस्तेमाल करें.
विज़िबिलिटी और सिंबॉलिक मैक्रो
इस सेक्शन में बताया गया है कि विज़िबिलिटी सिस्टम, सिंबॉलिक मैक्रो के साथ कैसे इंटरैक्ट करता है.
सिंबॉलिक मैक्रो में मौजूद जगहें
विज़िबिलिटी सिस्टम की एक अहम जानकारी यह है कि हम किसी एलान की जगह कैसे तय करते हैं. सिंबॉलिक मैक्रो में तय नहीं किए गए टारगेट के लिए, जगह सिर्फ़ वह पैकेज होता है जहां टारगेट मौजूद है. यानी, BUILD फ़ाइल का पैकेज.
हालांकि, सिंबॉलिक मैक्रो में बनाए गए टारगेट के लिए, जगह वह पैकेज होता है जिसमें .bzl फ़ाइल मौजूद है. इस फ़ाइल में, मैक्रो की परिभाषा (my_macro = macro(...) स्टेटमेंट) दिखती है. जब किसी टारगेट को नेस्ट किए गए कई टारगेट के अंदर बनाया जाता है, तो हमेशा सबसे अंदर मौजूद सिंबॉलिक मैक्रो की परिभाषा का इस्तेमाल किया जाता है.
किसी दी गई डिपेंडेंसी की विज़िबिलिटी की जांच करने के लिए, किस जगह का इस्तेमाल किया जाए, यह तय करने के लिए भी इसी सिस्टम का इस्तेमाल किया जाता है. अगर इस्तेमाल करने वाला टारगेट, किसी मैक्रो के अंदर बनाया गया है, तो हम इस्तेमाल करने वाले टारगेट के पैकेज के बजाय, सबसे अंदर मौजूद मैक्रो की परिभाषा देखते हैं.
इसका मतलब है कि एक ही पैकेज में तय किए गए कोड वाले सभी मैक्रो, अपने-आप "दोस्त" बन जाते हैं. `//lib:defs.bzl` में तय किए गए किसी मैक्रो
से सीधे तौर पर बनाए गए किसी भी टारगेट को, `//lib` में तय किए गए किसी अन्य मैक्रो से देखा जा सकता है.
भले ही, मैक्रो को असल में किन पैकेज में इंस्टैंशिएट किया गया हो. इसी तरह, वे //lib/BUILD और उसके पुराने मैक्रो में सीधे तौर पर तय किए गए टारगेट को देख सकते हैं. साथ ही, इन टारगेट को भी देखा जा सकता है. इसके उलट, एक ही पैकेज में मौजूद टारगेट, एक-दूसरे को नहीं देख सकते. ऐसा तब होता है, जब उनमें से कम से कम एक टारगेट, सिंबॉलिक मैक्रो से बनाया गया हो.
सिंबॉलिक मैक्रो के लागू करने वाले फ़ंक्शन में, visibility पैरामीटर की वैल्यू, मैक्रो के visibility एट्रिब्यूट की वैल्यू के बराबर होती है. इसमें, मैक्रो को कॉल करने की जगह जोड़ी जाती है. किसी मैक्रो के लिए, अपने किसी टारगेट को कॉल करने वाले को एक्सपोर्ट करने का स्टैंडर्ड तरीका यह है कि इस वैल्यू को टारगेट के एलान में फ़ॉरवर्ड किया जाए. जैसे, some_rule(..., visibility = visibility). जिन टारगेट में यह एट्रिब्यूट शामिल नहीं होता उन्हें मैक्रो को कॉल करने वाला नहीं देख पाएगा. ऐसा तब तक होगा, जब तक कि कॉल करने वाला, मैक्रो की परिभाषा वाले पैकेज में न हो. यह व्यवहार कंपोज़ होता है. इसका मतलब है कि सब-मैक्रो को नेस्ट किए गए कॉल की चेन में, हर कॉल visibility = visibility पास कर सकता है. इससे, अंदर मौजूद मैक्रो के एक्सपोर्ट किए गए टारगेट, हर लेवल पर कॉल करने वाले को फिर से एक्सपोर्ट किए जा सकते हैं. साथ ही, मैक्रो के लागू करने से जुड़ी कोई भी जानकारी ज़ाहिर नहीं होती.
सब-मैक्रो को विशेषाधिकार सौंपना
विज़िबिलिटी मॉडल में एक खास सुविधा होती है. इसकी मदद से, कोई मैक्रो अपने अनुमतियों को किसी सब-मैक्रो को सौंप सकता है. यह मैक्रो को फ़ैक्टर करने और कंपोज़ करने के लिए ज़रूरी है.
मान लें कि आपके पास एक मैक्रो my_macro है. यह किसी दूसरे पैकेज के नियम some_library का इस्तेमाल करके, डिपेंडेंसी एज बनाता है:
# //macro/defs.bzl
load("//lib:defs.bzl", "some_library")
def _impl(name, visibility, ...):
...
native.genrule(
name = name + "_dependency"
...
)
some_library(
name = name + "_consumer",
deps = [name + "_dependency"],
...
)
my_macro = macro(implementation = _impl, ...)
# //pkg/BUILD
load("//macro:defs.bzl", "my_macro")
my_macro(name = "foo", ...)
//pkg:foo_dependency टारगेट के लिए, visibility तय नहीं की गई है. इसलिए, यह सिर्फ़ //macro में दिखता है. यह इस्तेमाल करने वाले टारगेट के लिए ठीक है. अब, क्या होगा अगर //lib का लेखक, some_library को फिर से फ़ैक्टर करके, उसे मैक्रो का इस्तेमाल करके लागू करे?
# //lib:defs.bzl
def _impl(name, visibility, deps, ...):
some_rule(
# Main target, exported.
name = name,
visibility = visibility,
deps = deps,
...)
some_library = macro(implementation = _impl, ...)
इस बदलाव के बाद, //pkg:foo_consumer की जगह अब //macro के बजाय //lib है. इसलिए, //pkg:foo_dependency का इस्तेमाल करने से, डिपेंडेंसी की विज़िबिलिटी का उल्लंघन होता है. my_macro के लेखक से यह उम्मीद नहीं की जा सकती कि वह इस लागू करने से जुड़ी जानकारी से बचने के लिए, डिपेंडेंसी के एलान में
visibility = ["//lib"] पास करे.
इस वजह से, जब किसी टारगेट की डिपेंडेंसी, उस मैक्रो की एट्रिब्यूट वैल्यू भी होती है जिसने टारगेट का एलान किया है, तो हम डिपेंडेंसी की विज़िबिलिटी की जांच, इस्तेमाल करने वाले टारगेट की जगह के बजाय, मैक्रो की जगह के हिसाब से करते हैं.
इस उदाहरण में, यह पुष्टि करने के लिए कि //pkg:foo_consumer, //pkg:foo_dependency को देख सकता है या नहीं, हम देखते हैं कि //pkg:foo_dependency को my_macro के अंदर some_library को कॉल करने के लिए, इनपुट के तौर पर भी पास किया गया था. इसके बजाय, हम इस कॉल की जगह //macro के हिसाब से, डिपेंडेंसी की विज़िबिलिटी की जांच करते हैं.
यह प्रोसेस, बार-बार दोहराई जा सकती है. ऐसा तब तक होता है, जब तक किसी टारगेट या मैक्रो का एलान, किसी अन्य सिंबॉलिक मैक्रो के अंदर न हो. इस मैक्रो में, डिपेंडेंसी के लेबल को, लेबल-टाइप वाले किसी एट्रिब्यूट में लिया जाता है.
फ़ाइनलाइज़र
नियम के फ़ाइनलाइज़र (ऐसा सिंबॉलिक मैक्रो जिसमें finalizer = True हो),
सिंबॉलिक मैक्रो की विज़िबिलिटी के सामान्य
नियमों के मुताबिक टारगेट को देखने के अलावा, उन सभी टारगेट को भी देख सकते हैं जो फ़ाइनलाइज़र टारगेट के
पैकेज को दिखते हैं.
दूसरे शब्दों में, अगर native.existing_rules() पर आधारित किसी पुराने मैक्रो को फ़ाइनलाइज़र में माइग्रेट किया जाता है, तो फ़ाइनलाइज़र से तय किए गए टारगेट, अपनी पुरानी डिपेंडेंसी को अब भी देख पाएंगे.
ऐसे टारगेट तय किए जा सकते हैं जिन्हें फ़ाइनलाइज़र, native.existing_rules() का इस्तेमाल करके इंट्रॉस्पेक्ट कर सकता है. हालांकि, विज़िबिलिटी सिस्टम के तहत, इन्हें डिपेंडेंसी के तौर पर इस्तेमाल नहीं किया जा सकता. उदाहरण के लिए, अगर मैक्रो से तय किया गया कोई टारगेट, अपने पैकेज या फ़ाइनलाइज़र मैक्रो की परिभाषा को नहीं दिखता है और इसे फ़ाइनलाइज़र को डेलिगेट नहीं किया गया है, तो फ़ाइनलाइज़र ऐसे टारगेट को नहीं देख सकता. हालांकि, ध्यान दें कि native.existing_rules() पर आधारित कोई पुराना मैक्रो भी ऐसे टारगेट को नहीं देख पाएगा.
ट्रांज़िटिव विज़िबिलिटी
ट्रांज़िटिव विज़िबिलिटी एक ऐसा तरीका है जिससे यह तय किया जा सकता है कि किसी टारगेट पर कौन निर्भर हो सकता है. इसमें, इनडायरेक्ट डिपेंडेंसी भी शामिल है. यह, टारगेट विज़िबिलिटी के सामान्य सिस्टम से अलग लागू होती है. इसलिए, डिपेंडेंसी चेन में हर लिंक के मान्य होने पर भी, ट्रांज़िटिव विज़िबिलिटी से जुड़ी गड़बड़ी हो सकती है. इससे टारगेट का लेखक, इसे क्लाइंट टारगेट के भरोसेमंद सेट के साथ शेयर कर सकता है. साथ ही, यह पक्का किया जा सकता है कि यह गलती से बिल्ड के बाकी हिस्सों में न दिखे.
ट्रांज़िटिव विज़िबिलिटी को पैकेज लेवल पर तय किया जाता है. इसके लिए, [package][package] फ़ंक्शन के transitive_visibility पैरामीटर का इस्तेमाल किया जाता है. यह एलान, पैकेज के सभी टारगेट पर लागू होता है. पैरामीटर में, package_group का एक लेबल दिया जाता है. इससे उन पैकेज के बारे में पता चलता है जिनके टारगेट, इस पैकेज के टारगेट पर ट्रांज़िटिव तरीके से निर्भर हो सकते हैं.
# //third_party/sensitive_dep/BUILD
package(
# This must be explicitly listed
transitive_visibility = [":sensitive_dep_users"]
)
package_group(
name = "sensitive_dep_users",
packages = [
"//third_party/sensitive_dep/...", # has to include itself
"//allowed",
],
)
sh_library(
name = "sensitive_dep"
)
# //not_allowed/BUILD
sh_binary(
name = "bad",
deps = ["//third_party/sensitive_dep:sensitive_dep"]
)
//not_allowed:bad को बनाने पर, यह गड़बड़ी दिखती है. यह //third_party/sensitive_dep:sensitive_dep पर निर्भर है, लेकिन यह इसकी transitive_visibility का हिस्सा नहीं है:
Transitive visibility error: //third_party/sensitive_dep:sensitive_dep is not transitively visible from ///not_allowed:bad. //"//third_party/sensitive_dep:sensitive_dep inherits a transitive_visibility declaration from its package or one of its dependencies that does not allow //not_allowed:bad.
transitive_visibility में इस्तेमाल किए गए पैकेज ग्रुप, अन्य पैकेज ग्रुप को include नहीं कर सकते.
ध्यान दें कि अगर किसी टारगेट की ट्रांज़िटिव डिपेंडेंसी पर ट्रांज़िटिव विज़िबिलिटी की पाबंदी है, तो वह टारगेट खुद भी पाबंदी को इनहेरिट करता है और इसे उन टारगेट को पास करता है जो उस पर निर्भर हैं. अगर किसी टारगेट की कई ट्रांज़िटिव डिपेंडेंसी पर ट्रांज़िटिव विज़िबिलिटी की पाबंदी है, तो उसे सभी पाबंदियों को पूरा करना होगा.
ट्रांज़िटिव विज़िबिलिटी, सिंबॉलिक मैक्रो में तय किए गए टारगेट पर भी लागू होती है. हालांकि, टारगेट विज़िबिलिटी के सामान्य सिस्टम के उलट, यह सिर्फ़ उन पैकेज को ध्यान में रखता है जिनमें ये टारगेट मौजूद हैं. यह उस पैकेज को ध्यान में नहीं रखता जिसने सिंबॉलिक मैक्रो को तय किया है.
लोड विज़िबिलिटी
लोड विज़िबिलिटी से यह कंट्रोल किया जाता है कि मौजूदा पैकेज के बाहर मौजूद अन्य BUILD या .bzl फ़ाइलों से, किसी .bzl फ़ाइल को लोड किया जा सकता है या नहीं.
जिस तरह टारगेट विज़िबिलिटी, टारगेट में शामिल सोर्स कोड को सुरक्षित रखती है, उसी तरह लोड विज़िबिलिटी, .bzl फ़ाइलों में शामिल बिल्ड लॉजिक को सुरक्षित रखती है. उदाहरण के लिए, BUILD फ़ाइल का लेखक, बार-बार तय किए जाने वाले कुछ टारगेट को .bzl फ़ाइल में मौजूद किसी मैक्रो में फ़ैक्टर करना चाहेगा. लोड विज़िबिलिटी की सुरक्षा के बिना, हो सकता है कि उसी वर्कस्पेस में मौजूद अन्य सहयोगी, उसके मैक्रो का फिर से इस्तेमाल करें. इससे मैक्रो में बदलाव करने पर, अन्य टीमों के बिल्ड में गड़बड़ी हो सकती है.
ध्यान दें कि किसी .bzl फ़ाइल का सोर्स फ़ाइल टारगेट हो भी सकता है और नहीं भी.
अगर ऐसा है, तो इस बात की कोई गारंटी नहीं है कि लोड विज़िबिलिटी और टारगेट विज़िबिलिटी एक जैसी होंगी. इसका मतलब है कि हो सकता है कि एक ही BUILD फ़ाइल, .bzl फ़ाइल को लोड कर पाए, लेकिन उसे srcs के filegroup में शामिल न कर पाए या इसके उलट. इससे कभी-कभी उन नियमों के लिए समस्याएं हो सकती हैं जो .bzl फ़ाइलों को सोर्स कोड के तौर पर इस्तेमाल करना चाहते हैं. जैसे, दस्तावेज़ जनरेट करने या टेस्टिंग के लिए.
प्रोटोटाइप बनाने के लिए, --check_bzl_visibility=false सेट करके, लोड विज़िबिलिटी लागू करने की सुविधा बंद की जा सकती है. सबमिट किए गए कोड के लिए, --check_visibility=false की तरह, इसका इस्तेमाल नहीं किया जाना चाहिए.
लोड विज़िबिलिटी, Bazel 6.0 से उपलब्ध है.
लोड विज़िबिलिटी तय करना
किसी .bzl फ़ाइल की लोड विज़िबिलिटी सेट करने के लिए, फ़ाइल में
visibility() फ़ंक्शन को कॉल करें.
visibility() का आर्ग्युमेंट, पैकेज की खास जानकारी की सूची होती है. यह
packages के
package_group एट्रिब्यूट की तरह होती है. हालांकि, 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 फ़ाइल को ऐसी अनुमति वाली सूची में दिखाना पड़ सकता है जो कई छोटी अनुमति वाली सूचियों से बनी हो. यह इस तरह से काम करता है जैसे a
package_group अपने package_groups को अपने
includes एट्रिब्यूट के ज़रिए शामिल कर सकता है.
मान लें कि आप किसी लोकप्रिय मैक्रो को बंद कर रहे हैं. आपको इसे सिर्फ़ मौजूदा उपयोगकर्ताओं और अपनी टीम के पैकेज को दिखाना है. इसके लिए, यह कोड लिखा जा सकता है:
# //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 लिंट
Buildifier लिंट
की मदद से, उपयोगकर्ताओं को चेतावनी दी जाती है. यह चेतावनी तब दिखती है, जब उपयोगकर्ता internal
या private नाम की किसी डायरेक्ट्री से कोई फ़ाइल लोड करते हैं. ऐसा तब होता है, जब उपयोगकर्ता की फ़ाइल, उस
डायरेक्ट्री के पैरंट के तहत न हो. यह लिंट, लोड विज़िबिलिटी की सुविधा से पहले से मौजूद है. साथ ही, यह उन वर्कस्पेस में ज़रूरी नहीं है जहां .bzl फ़ाइलें, विज़िबिलिटी तय करती हैं.