این صفحه دو سیستم دید 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
استفاده کنید. این خوانایی را افزایش می دهد و از همگام شدن لیست ها جلوگیری می کند.
قانون رویت هدف
قابلیت مشاهده یک هدف قانون عبارت است از:
مقدار مشخصه
visibility
آن، اگر تنظیم شود؛ یا یه چیز دیگهمقدار آرگومان
default_visibility
دستورpackage
در فایلBUILD
هدف، در صورت وجود چنین اعلانی. یا یه چیز دیگه//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
. در آن قابلیت مشاهده را اعلام میکنند، ضروری نیست.