本頁面說明 Bazel 的兩種瀏覽權限系統: 目標瀏覽權限和負載瀏覽權限。
這兩種可見度設定都能協助其他開發人員區分您的程式庫公開 API 和實作詳細資料,並在您的工作區擴大時協助強制執行結構。您也可以在淘汰公開 API 時使用可見性,允許現有使用者使用,但拒絕新使用者。
目標瀏覽權限
目標瀏覽權限:控管哪些使用者可能取決於你的目標,也就是誰
在 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
的所有套件。- 套件群組會使用
各種語法
指定套件在套件群組中
"//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/...
來源樹狀結構的一部分,以及已定義的目標
在 //tests/BUILD
中,但不受 //tests/integration/BUILD
中定義的目標影響。
最佳做法:如要讓多個目標顯示相同的套件組合,請使用 package_group
,而不要在每個目標的 visibility
屬性中重複列出清單。這麼做可提高可讀性,並避免清單不同步。
規則目標瀏覽權限
規則目標的瀏覽權限如下:
其
visibility
屬性的值 (如有設定)。或其他目標
BUILD
檔案中package
陳述式的default_visibility
引數值 (如果有此宣告);否則//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
的值:
如果已設定旗標,則瀏覽權限為「私人」。
否則會套用舊版行為:瀏覽權限與
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 並未強制執行 select()
鍵中參照的 config_setting
目標的顯示設定。有
有兩個標記,可用來移除這個舊版行為:
--incompatible_enforce_config_setting_visibility
啟用瀏覽權限檢查這些目標為協助進行遷移 也會導致任何未指定visibility
的config_setting
會視為公開 (無論套件層級default_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++ 編譯器
目前,為了方便查看,這些隱含的依附元件會視為其他依附元件。也就是說,每個規則的例項都必須能看到所依附的目標 (例如 C++ 編譯器)。實際操作 通常意味著目標必須具有公開的瀏覽權限。
如要變更這項行為,請設定 --incompatible_visibility_private_attributes_at_definition
。啟用後,問題中的目標只需對宣告為隱含依附元件的規則可見。也就是說,只有包含 .bzl
的套件可以查看此項目
檔案。在本範例中,C++ 編譯器可以是
就能避免系統
cc_library
規則。
載入瀏覽權限
載入可見度可控制是否可從其他 BUILD
或 .bzl
檔案載入 .bzl
檔案。
以相同方式保護封裝的原始碼
負載瀏覽權限可保護由 .bzl
封裝的建構邏輯
檔案。舉例來說,BUILD
檔案作者可能會將部分重複的目標定義納入 .bzl
檔案中的巨集。沒有負載防護
瀏覽權限時,他們可能會發現其他協作者在
以防修改巨集造成其他團隊建構應用程式
請注意,.bzl
檔案不一定有對應的來源檔案目標。
如果是這樣,則無法保證載入可見度和目標可見度會一致。也就是說,同一個 BUILD
檔案或許也能載入
.bzl
檔案,但並未列在 filegroup
的 srcs
中,
反之亦然這有時會導致規則無法使用 .bzl
檔案做為來源碼,例如無法產生文件或進行測試。
進行原型設計時,您可以透過
--check_bzl_visibility=false
。和 --check_visibility=false
一樣,這個項目應該
未完成的標記作業
自 Bazel 6.0 起才能使用載入瀏覽權限。
宣告負載瀏覽權限
如要設定 .bzl
檔案的載入瀏覽權限,請呼叫
檔案中的 visibility()
函式。
visibility()
的引數是套件規範清單,就像 package_group
的 packages
屬性一樣。不過,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
檔案的許可清單
由多個較小的許可清單組成。這與 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 建構工具 Lint
當使用者從名為 internal
或 private
的目錄載入檔案時,如果使用者的檔案本身並未位於該目錄的父項下方,系統就會提供警告的Buildifier lint。這項 Lint 會在載入可見度功能之前執行,因此在 .bzl
檔案宣告可見度的工作區中,這項 Lint 就沒有必要。