दृश्यता

इस पेज पर, 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 के सभी पैकेज को ऐक्सेस करने की अनुमति देता है जो का हिस्सा हैं.

उदाहरण के लिए, अगर //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 को सार्वजनिक के तौर पर भी मानता है. भले ही, पैकेज-लेवल पर default_visibility कुछ भी हो. ऐसा तब होता है, जब config_setting में visibility तय नहीं की गई हो.

  • --incompatible_config_setting_private_default_visibility से, config_setting में visibility तय न होने पर, पैकेज की default_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() पर आधारित कोई पुराना मैक्रो भी ऐसे टारगेट को नहीं देख पाएगा.

लोड विज़िबिलिटी

लोड विज़िबिलिटी से यह कंट्रोल किया जाता है कि मौजूदा पैकेज के बाहर मौजूद अन्य 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 फ़ाइलें, विज़िबिलिटी तय करती हैं.