دید

این صفحه دو سیستم دید Bazel را پوشش می دهد: دید هدف و دید بار .

هر دو نوع مشاهده به سایر توسعه دهندگان کمک می کند بین API عمومی کتابخانه شما و جزئیات پیاده سازی آن تمایز قائل شوند و با رشد فضای کاری شما به اجرای ساختار کمک می کند. همچنین می‌توانید هنگام منسوخ کردن یک API عمومی از قابلیت مشاهده استفاده کنید تا به کاربران فعلی اجازه دهید و در عین حال کاربران جدید را رد کنید.

دید هدف

نمایان بودن هدف را کنترل می کند که ممکن است به هدف شما بستگی داشته باشد - یعنی چه کسی ممکن است از برچسب هدف شما در یک ویژگی مانند deps استفاده کند.

یک هدف 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 داده شده هستند دسترسی می دهد.

    • گروه های بسته از نحو متفاوتی برای تعیین بسته ها استفاده می کنند. در یک گروه بسته، فرم‌های "//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/... استفاده شود. //some/package/... درخت منبع، و همچنین اهداف تعریف شده در //tests/BUILD ، اما نه توسط اهداف تعریف شده در //tests/integration/BUILD .

بهترین روش: برای قابل مشاهده کردن چندین هدف برای یک مجموعه از بسته ها، به جای تکرار لیست در ویژگی visibility هر هدف، از یک package_group استفاده کنید. این خوانایی را افزایش می دهد و از همگام شدن لیست ها جلوگیری می کند.

قانون رویت هدف

قابلیت مشاهده یک هدف قانون عبارت است از:

  1. مقدار مشخصه visibility آن، اگر تنظیم شود؛ یا یه چیز دیگه

  2. مقدار آرگومان default_visibility دستور package در فایل BUILD هدف، در صورت وجود چنین اعلانی. یا یه چیز دیگه

  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 می‌توانید به‌صراحت قابلیت مشاهده یک هدف فایل منبع را تنظیم کنید. وقتی هیچ آرگومان visibility به exports_files ، نمایان بودن را عمومی می‌کند. exports_files ممکن است برای نادیده گرفتن قابلیت مشاهده یک فایل تولید شده استفاده نشود.

برای اهداف فایل منبع که در فراخوانی به exports_files ظاهر نمی شوند، قابلیت مشاهده به مقدار flag --incompatible_no_implicit_file_export بستگی دارد:

  • اگر پرچم تنظیم شده باشد، قابلیت مشاهده خصوصی است.

  • در غیر این صورت، رفتار قدیمی اعمال می‌شود: قابلیت مشاهده مانند default_visibility فایل BUILD است، یا اگر دید پیش‌فرض مشخص نشده باشد، خصوصی است.

از تکیه بر رفتار میراثی خودداری کنید. هر زمان که هدف فایل منبع نیاز به مشاهده غیر خصوصی داشت، همیشه یک اعلان exports_files .

بهترین روش: در صورت امکان، ترجیح دهید یک هدف قانون را به جای یک فایل منبع افشا کنید. به عنوان مثال، به جای فراخوانی exports_files در یک .java ، فایل را در یک هدف 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 هایی که قابلیت مشاهده را برای رعایت default_visibility visibility بسته و بازگشت به نمای خصوصی مشخص نمی‌کنند، درست مانند هر هدف قانون دیگری، ایجاد می‌کند. اگر --incompatible_enforce_config_setting_visibility تنظیم نشده باشد، غیرفعال است.

از تکیه بر رفتار میراثی خودداری کنید. هر config_setting که برای استفاده در خارج از بسته فعلی در نظر گرفته شده است باید visibility واضحی داشته باشد، اگر بسته از قبل یک default_visibility مناسب را مشخص نکرده باشد.

قابلیت مشاهده هدف گروه بسته

اهداف package_group دارای ویژگی visibility نیستند. آنها همیشه در معرض دید عموم هستند.

قابلیت مشاهده وابستگی های ضمنی

برخی از قوانین وابستگی‌های ضمنی دارند - وابستگی‌هایی که در فایل BUILD مشخص نشده‌اند، اما ذاتی هر نمونه از آن قانون هستند. به عنوان مثال، یک قانون cc_library ممکن است یک وابستگی ضمنی از هر یک از اهداف قانون خود به یک هدف اجرایی که یک کامپایلر ++C را نشان می دهد ایجاد کند.

در حال حاضر، برای اهداف قابل مشاهده، این وابستگی های ضمنی مانند هر وابستگی دیگری در نظر گرفته می شوند. این بدان معنی است که هدفی که به آن وابسته است (مانند کامپایلر ++C ما) باید برای هر نمونه از قانون قابل مشاهده باشد. در عمل این معمولاً به این معنی است که هدف باید دید عمومی داشته باشد.

می توانید این رفتار را با تنظیم --incompatible_visibility_private_attributes_at_definition تغییر دهید. وقتی فعال باشد، هدف مورد نظر فقط باید برای قاعده ای که آن را یک وابستگی ضمنی اعلام می کند قابل مشاهده باشد. یعنی باید برای بسته حاوی فایل .bzl . که قانون در آن تعریف شده است قابل مشاهده باشد. در مثال ما، کامپایلر C++ تا زمانی که در همان بسته تعریف قانون cc_library زندگی می‌کند، می‌تواند خصوصی باشد.

دید بار

نمایان بودن بار کنترل می کند که آیا یک فایل .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() را فراخوانی نمی کنند همیشه از هر نقطه ای در فضای کاری قابل بارگیری هستند. ایده خوبی است که visibility("private") را به بالای هر فایل .bzl جدیدی که به طور خاص برای استفاده در خارج از بسته در نظر گرفته نشده است، اضافه کنید.

مثال

# //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 می تواند سایر گروه های package_group را includes طریق ویژگی include خود ترکیب کند.

فرض کنید در حال منسوخ کردن یک ماکرو پرکاربرد هستید. شما می‌خواهید که فقط برای کاربران موجود و بسته‌های متعلق به تیم شما قابل مشاهده باشد. ممکن است بنویسید:

# //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. منتقل کنید، جایی که هر دو نوع اعلان ممکن است به آن اشاره کنند. با استفاده از مثال در Factoring Visibilities بالا، ممکن است بنویسید:

# //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 . در آن قابلیت مشاهده را اعلام می‌کنند، ضروری نیست.