דף זה מכסה את שתי מערכות החשיפה של Bazel': יעד החשיפה וחשיפה של טעינה.
שני סוגי החשיפה עוזרים למפתחים אחרים להבחין בין ה-API הציבורי של הספרייה שלך לבין פרטי ההטמעה שלה, ועוזרים לאכוף את המבנה כשסביבת העבודה גדלה. תוכלו גם לראות את הזמינות של ההוצאה משימוש של ממשק API ציבורי, כדי לאפשר למשתמשים הקיימים לדחות הרשאות של משתמשים חדשים.
החשיפה של היעד
חשיפה ליעד קובעת מי עשוי להיות תלוי ביעד שלך – כלומר, מי עשוי להשתמש בתווית של היעד בתוך מאפיין כמו deps
.
יעד A
גלוי ליעד B
אם הוא נמצא באותה חבילה, או אם
A
מעניק חשיפה לחבילה B
&33. לכן, חבילות הן היחידה של רמת הפירוט, שמאפשרת להחליט אם לאפשר גישה או לא. אם השדה B
תלוי ב-A
אבל A
לא גלוי ל-B
, כל ניסיון לבנות B
ייכשל במהלך הניתוח.
שימו לב: הענקת חשיפה לחבילה לא מעניקה בעצמה חשיפה לחבילות המשנה. פרטים נוספים על חבילות וחבילות משנה זמינים במאמר מושגים ומונחים.
לצורך יצירת אב טיפוס, ניתן להשבית את האכיפה של הרשאות הגישה על ידי הגדרת הסימון --check_visibility=false
. אין להשתמש באפשרות הזו לשימוש בסביבת ייצור בקוד שנשלח.
הדרך העיקרית לשלוט בחשיפה היא באמצעות המאפיין visibility
ביעדים של כללים. קטע זה מתאר את הפורמט של המאפיין הזה, ואיך לקבוע את הרשאות הגישה של יעד.
מפרט הרשאות גישה
לכל יעדי הכללים יש מאפיין visibility
שמקבל רשימת תוויות. לכל תווית יש אחד מהטפסים הבאים. למעט הטופס האחרון, אלה רק placeholders תחביריים שלא תואמים לאף יעד בפועל.
"//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"
.
- לקבוצות חבילות יש תחביר שונה לציון חבילות ספציפיות. במסגרת חבילת חבילות, הטפסים
לדוגמה, אם המאפיין visibility
מוגדר ל-//some/package:mytarget
,
ניתן להשתמש בו לכל יעד שהוא חלק מעץ המקור של //some/package/...
, וגם ליעדים שהוגדרו ב-//tests/BUILD
, אבל לא ליעדים שהוגדרו ב-//tests/integration/BUILD
.
שיטה מומלצת: כדי להפוך כמה יעדים לגלויים לאותה קבוצת חבילות, אפשר להשתמש ב-package_group
במקום לחזור לרשימה בכל מאפיין visibility
של יעד. כך ניתן לקרוא יותר ולמנוע את הסנכרון של הרשימות.
החשיפה של יעד הכלל
הנראות של כלל היעד היא:
הערך של המאפיין
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
, הרשאות הגישה תלויות בערך הדגל
--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
שלא מצייניםvisibility
לכבד אתdefault_visibility
החבילהdefault_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
.
באופן דומה, חשיפת היעד מגנה על קוד המקור שמורחב על ידי יעדים, וגם חשיפת הטעינה מגנה על לוגיקת build הכלולה בקובצי .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
.
נניח שמוציאים משימוש מאקרו נפוץ. אתם רוצים שהוא יהיה גלוי רק למשתמשים קיימים ולחבילות שבבעלות הצוות שלכם. אפשר לכתוב:
# //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
מוך build של Bzl
יש קונטיינר של build שמספק אזהרה אם משתמשים טוענים קובץ מהספרייה בשם internal
או private
, כאשר הקובץ של המשתמש לא נמצא מתחת להורה של אותה ספרייה. המוך הזה מוקדם יותר מתכונת החשיפה של הטעינה, והוא מיותר בסביבות עבודה שבהן קובצי .bzl
מצהירים על חשיפות.