दृश्यता

इस पेज पर, 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 को पैकेज की default_visibility के हिसाब से विज़िबिलिटी देता है. अगर visibility तय नहीं की गई है, तो यह फ़्लैग, निजी विज़िबिलिटी का इस्तेमाल करता है. यह ठीक उसी तरह काम करता है जैसे नियम का कोई अन्य टारगेट. अगर --incompatible_enforce_config_setting_visibility फ़्लैग सेट नहीं किया गया है, तो यह फ़्लैग कोई कार्रवाई नहीं करता.

पुराने तरीके पर निर्भर न रहें. अगर कोई config_setting, मौजूदा पैकेज के बाहर इस्तेमाल किया जाना है और पैकेज में तय नहीं की गई है, तो उसमें visibility साफ़ तौर पर तय की जानी चाहिए.default_visibility

पैकेज ग्रुप के टारगेट की विज़िबिलिटी

package_group टारगेट में, visibility एट्रिब्यूट नहीं होता. ये हमेशा सार्वजनिक तौर पर दिखते हैं.

इनडायरेक्ट डिपेंडेंसी की विज़िबिलिटी

कुछ नियमों में इनडायरेक्ट डिपेंडेंसी होती हैं — ये ऐसी डिपेंडेंसी होती हैं जिन्हें BUILD फ़ाइल में तय नहीं किया जाता. हालांकि, ये उस नियम के हर इंस्टेंस में मौजूद होती हैं. उदाहरण के लिए, cc_library नियम, अपने हर नियम के टारगेट से, C++ कंपाइलर को दिखाने वाले एक्ज़ीक्यूटेबल टारगेट तक, इनडायरेक्ट डिपेंडेंसी बना सकता है.

ऐसी इनडायरेक्ट डिपेंडेंसी की विज़िबिलिटी की जांच, उस पैकेज के हिसाब से की जाती है जिसमें .bzl फ़ाइल मौजूद है. इस फ़ाइल में, नियम (या आसपेक्ट) तय किया जाता है. हमारे उदाहरण में, C++ कंपाइलर को निजी रखा जा सकता है. हालांकि, इसके लिए ज़रूरी है कि वह cc_library नियम की परिभाषा वाले पैकेज में ही मौजूद हो. अगर इनडायरेक्ट डिपेंडेंसी, परिभाषा से नहीं दिखती है, तो उसकी जांच cc_library टारगेट के हिसाब से की जाती है.

अगर आपको किसी नियम के इस्तेमाल को कुछ पैकेज तक सीमित रखना है, तो इसके बजाय लोड विज़िबिलिटी का इस्तेमाल करें.

विज़िबिलिटी और सिंबॉलिक मैक्रो

इस सेक्शन में बताया गया है कि विज़िबिलिटी सिस्टम, सिंबॉलिक मैक्रो के साथ कैसे इंटरैक्ट करता है.

सिंबॉलिक मैक्रो में मौजूद जगहें

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

उदाहरण

# //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 अपने 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 लिंट

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