Halaman ini membahas dua sistem visibilitas Bazel: visibilitas target dan visibilitas pemuatan.
Kedua jenis visibilitas ini membantu developer lain membedakan antara API publik library Anda dan detail implementasinya, serta membantu menerapkan struktur saat ruang kerja Anda berkembang. Anda juga dapat menggunakan visibilitas saat menghentikan penggunaan API publik untuk mengizinkan pengguna saat ini, sekaligus menolak pengguna baru.
Visibilitas target
Visibilitas target mengontrol siapa yang dapat bergantung pada target Anda, yaitu siapa yang dapat menggunakan label target Anda di dalam atribut seperti deps.
Target A terlihat oleh target B jika keduanya berada dalam paket yang sama, atau jika A memberikan visibilitas ke paket B. Oleh karena itu, paket adalah unit granularitas untuk memutuskan apakah akan mengizinkan akses atau tidak. Jika B bergantung pada A
tetapi A tidak terlihat oleh B, upaya apa pun untuk mem-build B akan gagal selama
analisis.
Perhatikan bahwa pemberian visibilitas ke paket tidak dengan sendirinya memberikan visibilitas ke subpaketnya. Untuk mengetahui detail selengkapnya tentang paket dan subpaket, lihat Konsep dan terminologi.
Untuk pembuatan prototipe, Anda dapat menonaktifkan penerapan visibilitas target dengan menetapkan flag --check_visibility=false. Tindakan ini tidak boleh dilakukan untuk penggunaan produksi dalam kode yang dikirimkan.
Cara utama untuk mengontrol visibilitas adalah dengan atribut
visibility pada
target aturan. Bagian ini menjelaskan format atribut ini, dan cara menentukan visibilitas target.
Spesifikasi visibilitas
Semua target aturan memiliki atribut visibility yang menggunakan daftar label. Setiap label memiliki salah satu bentuk berikut. Dengan pengecualian bentuk terakhir, ini hanyalah placeholder sintaksis yang tidak sesuai dengan target sebenarnya.
"//visibility:public": Memberikan akses ke semua paket. (Tidak dapat digabungkan dengan spesifikasi lainnya.)"//visibility:private": Tidak memberikan akses tambahan apa pun; hanya target dalam paket ini yang dapat menggunakan target ini. (Tidak dapat digabungkan dengan spesifikasi lainnya.)"//foo/bar:__pkg__": Memberikan akses ke//foo/bar(tetapi bukan subpaketnya)."//foo/bar:__subpackages__": Memberikan akses//foo/bardan semua subpaket langsung dan tidak langsungnya."//some_pkg:my_package_group": Memberikan akses ke semua paket yang merupakan bagian daripackage_groupyang diberikan.- Grup paket menggunakan sintaksis yang
berbeda untuk
menentukan paket. Dalam grup paket, bentuk
"//foo/bar:__pkg__"dan"//foo/bar:__subpackages__"masing-masing diganti dengan"//foo/bar"dan"//foo/bar/...". Demikian pula,"//visibility:public"dan"//visibility:private"hanyalah"public"dan"private".
- Grup paket menggunakan sintaksis yang
berbeda untuk
menentukan paket. Dalam grup paket, bentuk
Misalnya, jika //some/package:mytarget memiliki visibility yang ditetapkan ke
[":__subpackages__", "//tests:__pkg__"], target tersebut dapat digunakan oleh target apa pun
yang merupakan bagian dari pohon sumber //some/package/..., serta target yang ditentukan
di //tests/BUILD, tetapi tidak oleh target yang ditentukan di //tests/integration/BUILD.
Praktik terbaik: Untuk membuat beberapa target terlihat oleh kumpulan paket yang sama, gunakan package_group, bukan mengulangi daftar di setiap atribut visibility target. Hal ini meningkatkan keterbacaan dan mencegah daftar menjadi tidak sinkron.
Visibilitas target aturan
Visibilitas target aturan adalah:
Nilai atribut
visibility, jika ditetapkan; atauNilai argumen
default_visibilitydari pernyataanpackagedalam fileBUILDtarget, jika deklarasi tersebut ada; atau//visibility:private.
Praktik terbaik: Hindari menetapkan default_visibility ke publik. Hal ini mungkin mudah untuk pembuatan prototipe atau dalam codebase kecil, tetapi risiko pembuatan target publik secara tidak sengaja akan meningkat seiring dengan pertumbuhan codebase. Sebaiknya tentukan secara eksplisit target mana yang merupakan bagian dari antarmuka publik paket.
Contoh
File //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"],
)
File //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",
],
)
Visibilitas target file yang dihasilkan
Target file yang dihasilkan memiliki visibilitas yang sama dengan target aturan yang menghasilkannya.
Visibilitas target file sumber
Anda dapat menetapkan visibilitas target file sumber secara eksplisit dengan memanggil
exports_files. Jika tidak ada argumen visibility yang diteruskan ke exports_files, visibilitas akan ditetapkan ke publik.
exports_files tidak dapat digunakan untuk mengganti visibilitas file yang dihasilkan.
Untuk target file sumber yang tidak muncul dalam panggilan ke exports_files, visibilitas bergantung pada nilai flag
--incompatible_no_implicit_file_export:
Jika flag ditetapkan, visibilitasnya adalah pribadi.
Jika tidak, perilaku lama akan berlaku: Visibilitasnya sama dengan
default_visibilityfileBUILD, atau pribadi jika visibilitas default tidak ditentukan.
Hindari mengandalkan perilaku lama. Selalu tulis deklarasi exports_files setiap kali target file sumber memerlukan visibilitas non-pribadi.
Praktik terbaik: Jika memungkinkan, sebaiknya ekspos target aturan, bukan file sumber. Misalnya, daripada memanggil exports_files pada file .java, gabungkan file dalam target java_library non-pribadi. Umumnya, target aturan hanya boleh langsung mereferensikan file sumber yang berada dalam paket yang sama.
Contoh
File //frobber/data/BUILD:
exports_files(["readme.txt"])
File //frobber/bin/BUILD:
cc_binary(
name = "my-program",
data = ["//frobber/data:readme.txt"],
)
Visibilitas setelan konfigurasi
Secara historis, Bazel tidak menerapkan visibilitas untuk
config_setting target yang
direferensikan dalam kunci select(). Ada dua flag untuk menghapus perilaku lama ini:
--incompatible_enforce_config_setting_visibilitymengaktifkan pemeriksaan visibilitas untuk target ini. Untuk membantu migrasi, flag ini juga menyebabkanconfig_settingapa pun yang tidak menentukanvisibilitydianggap publik (terlepas daridefault_visibilitytingkat paket).--incompatible_config_setting_private_default_visibilitymenyebabkanconfig_settingyang tidak menentukanvisibilityuntuk mematuhi paketdefault_visibilitydan kembali ke visibilitas pribadi, seperti target aturan lainnya. Tindakan ini tidak akan berpengaruh jika--incompatible_enforce_config_setting_visibilitytidak ditetapkan.
Hindari mengandalkan perilaku lama. `config_setting` apa pun yang dimaksudkan untuk
digunakan di luar paket saat ini harus memiliki visibility`visibility` eksplisit, jika
paket belum menentukan default_visibility`default_visibility` yang sesuai.config_setting
Visibilitas target grup paket
Target package_group tidak memiliki atribut visibility. Target ini selalu terlihat secara publik.
Visibilitas dependensi implisit
Beberapa aturan memiliki dependensi implisit —
dependensi yang tidak dieja dalam file BUILD, tetapi melekat pada
setiap instance aturan tersebut. Misalnya, aturan cc_library dapat membuat dependensi implisit dari setiap target aturannya ke target yang dapat dieksekusi yang mewakili compiler C++.
Visibilitas dependensi implisit tersebut diperiksa sehubungan dengan paket yang berisi file .bzl tempat aturan (atau aspek) ditentukan. Dalam contoh kami, compiler C++ dapat bersifat pribadi selama berada dalam paket yang sama dengan definisi aturan cc_library. Sebagai penggantian, jika dependensi implisit tidak terlihat dari definisi, dependensi tersebut akan diperiksa sehubungan dengan target cc_library.
Anda dapat mengubah perilaku ini dengan menonaktifkan
--incompatible_visibility_private_attributes_at_definition.
Jika dinonaktifkan, dependensi implisit akan diperlakukan seperti dependensi lainnya.
Artinya, target yang bergantung (seperti compiler C++ kami) harus terlihat oleh setiap instance aturan. Dalam praktiknya, hal ini biasanya berarti target harus memiliki visibilitas publik.
Jika Anda ingin membatasi penggunaan aturan ke paket tertentu, gunakan visibilitas pemuatan sebagai gantinya.
Visibilitas pemuatan
Visibilitas pemuatan mengontrol apakah file .bzl dapat dimuat dari file BUILD atau .bzl lain di luar paket saat ini.
Dengan cara yang sama seperti visibilitas target melindungi kode sumber yang dienkapsulasi oleh target, visibilitas pemuatan melindungi logika build yang dienkapsulasi oleh file .bzl. Misalnya, penulis file BUILD mungkin ingin memfaktorkan beberapa definisi target berulang ke dalam makro dalam file .bzl. Tanpa perlindungan visibilitas pemuatan, mereka mungkin menemukan makro yang digunakan kembali oleh kolaborator lain di ruang kerja yang sama, sehingga memodifikasi makro akan merusak build tim lain.
Perhatikan bahwa file .bzl mungkin atau mungkin tidak memiliki target file sumber yang sesuai.
Jika ada, tidak ada jaminan bahwa visibilitas pemuatan dan visibilitas target akan bertepatan. Artinya, file BUILD yang sama mungkin dapat memuat file
.bzl tetapi tidak mencantumkannya di srcs dari filegroup,
atau sebaliknya. Hal ini terkadang dapat menyebabkan masalah untuk aturan yang ingin menggunakan file .bzl sebagai kode sumber, seperti untuk pembuatan atau pengujian dokumentasi.
Untuk pembuatan prototipe, Anda dapat menonaktifkan penerapan visibilitas pemuatan dengan menetapkan --check_bzl_visibility=false. Seperti --check_visibility=false, hal ini tidak boleh dilakukan untuk kode yang dikirimkan.
Visibilitas pemuatan tersedia mulai Bazel 6.0.
Mendeklarasikan visibilitas pemuatan
Untuk menetapkan visibilitas pemuatan file .bzl, panggil fungsi
visibility() dari dalam file.
Argumen untuk visibility() adalah daftar spesifikasi paket, seperti
atribut packages dari
package_group. Namun, visibility() tidak menerima spesifikasi paket negatif.
Panggilan ke visibility() hanya boleh terjadi satu kali per file, di tingkat atas (bukan di dalam fungsi), dan sebaiknya segera setelah pernyataan load().
Tidak seperti visibilitas target, visibilitas pemuatan default selalu publik. File yang tidak memanggil visibility() selalu dapat dimuat dari mana saja di ruang kerja. Sebaiknya tambahkan visibility("private") ke bagian atas file .bzl baru yang tidak secara khusus dimaksudkan untuk digunakan di luar paket.
Contoh
# //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
...
Praktik visibilitas pemuatan
Bagian ini menjelaskan tips untuk mengelola deklarasi visibilitas pemuatan.
Memfaktorkan visibilitas
Jika beberapa file .bzl harus memiliki visibilitas yang sama, sebaiknya faktorkan spesifikasi paketnya ke dalam daftar umum. Contoh:
# //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)
...
Hal ini membantu mencegah perbedaan yang tidak disengaja antara visibilitas berbagai file .bzl. Selain itu, kode ini lebih mudah dibaca jika daftar clients besar.
Menyusun visibilitas
Terkadang, file .bzl mungkin perlu terlihat oleh daftar yang diizinkan yang terdiri dari beberapa daftar yang diizinkan yang lebih kecil. Hal ini analog dengan cara a
package_group dapat menggabungkan package_group lain melalui atribut
includes.
Misalkan Anda menghentikan penggunaan makro yang banyak digunakan. Anda ingin makro tersebut hanya terlihat oleh pengguna yang ada dan paket yang dimiliki oleh tim Anda sendiri. Anda dapat menulis:
# //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)
Menghapus duplikat dengan grup paket
Tidak seperti visibilitas target, Anda tidak dapat menentukan visibilitas pemuatan dalam hal package_group. Jika Anda ingin menggunakan kembali daftar yang diizinkan yang sama untuk visibilitas target dan visibilitas pemuatan, sebaiknya pindahkan daftar spesifikasi paket ke file .bzl, tempat kedua jenis deklarasi dapat merujuknya. Dengan menggunakan contoh di Memfaktorkan visibilitas
di atas, Anda dapat menulis:
# //mylib/BUILD
load(":internal_defs", "clients")
package_group(
name = "my_pkg_grp",
packages = clients,
)
Hal ini hanya berfungsi jika daftar tidak berisi spesifikasi paket negatif.
Melindungi simbol individual
Simbol Starlark apa pun yang namanya diawali dengan garis bawah tidak dapat dimuat dari file lain. Hal ini memudahkan pembuatan simbol pribadi, tetapi tidak memungkinkan Anda membagikan simbol ini dengan kumpulan file tepercaya yang terbatas. Di sisi lain, visibilitas pemuatan memberi Anda kontrol atas paket lain yang dapat melihat .bzl file, tetapi tidak memungkinkan Anda mencegah simbol non-garis bawah dimuat.
Untungnya, Anda dapat menggabungkan kedua fitur ini untuk mendapatkan kontrol yang lebih mendetail.
# //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
Lint Buildifier bzl-visibility
Ada lint Buildifier
yang memberikan peringatan jika pengguna memuat file dari direktori yang diberi nama internal
atau private, saat file pengguna tidak berada di bawah induk
direktori tersebut. Lint ini mendahului fitur visibilitas pemuatan dan tidak diperlukan di ruang kerja tempat file .bzl mendeklarasikan visibilitas.