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