दृश्यता

इस पेज पर, Bazel की दो विज़िबिलिटी सिस्टम के बारे में बताया गया है: टारगेट विज़िबिलिटी और लोड विज़िबिलिटी.

विज़िबिलिटी के दोनों टाइप से, अन्य डेवलपर को आपकी लाइब्रेरी के सार्वजनिक एपीआई और उसके लागू करने से जुड़ी जानकारी के बीच अंतर करने में मदद मिलती है. साथ ही, आपका वर्कस्पेस बढ़ने पर, स्ट्रक्चर को लागू करने में भी मदद मिलती है. सार्वजनिक एपीआई को बंद करते समय, विज़िबिलिटी का इस्तेमाल किया जा सकता है. इससे मौजूदा उपयोगकर्ताओं को एपीआई का ऐक्सेस दिया जा सकता है, जबकि नए उपयोगकर्ताओं को नहीं.

टारगेट विज़िबिलिटी

टारगेट विज़िबिलिटी से यह कंट्रोल किया जाता है कि आपके टारगेट पर कौन निर्भर हो सकता है. इसका मतलब है कि deps जैसे एट्रिब्यूट में, आपके टारगेट का लेबल कौन इस्तेमाल कर सकता है.

अगर टारगेट A और टारगेट B एक ही पैकेज में हैं या अगर A, B के पैकेज को विज़िबिलिटी देता है, तो A, B को दिखता है. इसलिए, पैकेज, ऐक्सेस की अनुमति देने या न देने का फ़ैसला करने के लिए, ग्रैन्युलैरिटी की यूनिट होते हैं. अगर B पर निर्भर है A लेकिन A को नहीं दिखता है B, तो बनाने की कोई भी कोशिश 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 का इस्तेमाल करें. इससे सूची को पढ़ने में आसानी होती है और सूची के सिंक से बाहर होने से रोका जा सकता है.

नियम के टारगेट की विज़िबिलिटी

नियम के टारगेट की विज़िबिलिटी:

  1. अगर सेट की गई है, तो उसके visibility एट्रिब्यूट की वैल्यू; या

  2. अगर ऐसा एलान मौजूद है, तो टारगेट की BUILD फ़ाइल में package स्टेटमेंट के default_visibilityआर्ग्युमेंट की वैल्यू; या

  3. //visibility:private.

सबसे सही तरीका: default_visibility को सार्वजनिक पर सेट करने से बचें. प्रोटोटाइप बनाने या छोटे कोडबेस के लिए, यह सुविधाजनक हो सकता है. हालांकि, कोडबेस बढ़ने पर, गलती से सार्वजनिक टारगेट बनाने का खतरा बढ़ जाता है. यह साफ़ तौर पर बताना बेहतर है कि कौनसे टारगेट, किसी पैकेज के सार्वजनिक इंटरफ़ेस का हिस्सा हैं.

उदाहरण

//frobber/bin/BUILD फ़ाइल:

# This target is visible to everyone
cc_binary(
    name = "executable",
    visibility = ["//visibility:public"],
    deps = [":library"],
)

# This target is visible only to targets declared in the same package
cc_library(
    name = "library",
    # No visibility -- defaults to private since no
    # package(default_visibility = ...) was used.
)

# This target is visible to targets in package //object and //noun
cc_library(
    name = "subject",
    visibility = [
        "//noun:__pkg__",
        "//object:__pkg__",
    ],
)

# See package group "//frobber:friends" (below) for who can
# access this target.
cc_library(
    name = "thingy",
    visibility = ["//frobber:friends"],
)

//frobber/BUILD फ़ाइल:

# This is the package group declaration to which target
# //frobber/bin:thingy refers.
#
# Our friends are packages //frobber, //fribber and any
# subpackage of //fribber.
package_group(
    name = "friends",
    packages = [
        "//fribber/...",
        "//frobber",
    ],
)

जनरेट की गई फ़ाइल के टारगेट की विज़िबिलिटी

जनरेट की गई फ़ाइल के टारगेट की विज़िबिलिटी, उसे जनरेट करने वाले नियम के टारगेट की विज़िबिलिटी के जैसी ही होती है.

सोर्स फ़ाइल के टारगेट की विज़िबिलिटी

` exports_files` को कॉल करके, सोर्स फ़ाइल के टारगेट की विज़िबिलिटी साफ़ तौर पर सेट की जा सकती है. जब exports_files को कोई visibility आर्ग्युमेंट नहीं दिया जाता है, तो यह विज़िबिलिटी को सार्वजनिक बना देता है. जनरेट की गई फ़ाइल की विज़िबिलिटी को ओवरराइड करने के लिए, exports_files का इस्तेमाल नहीं किया जा सकता.

सोर्स फ़ाइल के उन टारगेट के लिए जो 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 सेट नहीं है, तो यह कोई कार्रवाई नहीं करता.

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

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

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

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

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

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

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

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

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

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