दृश्यता

इस पेज पर, 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 ने select() की कुंजियों में रेफ़र किए गए config_setting टारगेट के लिए, विज़िबिलिटी लागू नहीं की थी. लेगसी वर्शन के इस व्यवहार को हटाने के लिए, दो फ़्लैग उपलब्ध हैं:

  • --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 फ़ाइल को लोड कर सकती है, लेकिन उसे 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-visibility Buildifier lint

Buildifier lint मौजूद है. यह उपयोगकर्ताओं को चेतावनी देता है, अगर वे internal या private नाम की किसी डायरेक्ट्री से कोई फ़ाइल लोड करते हैं. ऐसा तब होता है, जब उपयोगकर्ता की फ़ाइल उस डायरेक्ट्री के पैरंट डायरेक्ट्री में मौजूद न हो. यह लिंट, लोड विज़िबिलिटी की सुविधा से पहले का है. साथ ही, यह उन वर्कस्पेस में ज़रूरी नहीं है जहां .bzl फ़ाइलें विज़िबिलिटी तय करती हैं.