Halaman ini membahas dua sistem visibilitas Bazel: visibilitas target dan visibilitas muatan.
Kedua jenis visibilitas membantu developer lain membedakan antara API publik library Anda dan detail penerapannya, serta membantu menerapkan struktur seiring dengan berkembangnya ruang kerja Anda. Anda juga dapat menggunakan visibilitas saat menghentikan penggunaan API publik untuk mengizinkan pengguna saat ini dan menolak yang baru.
Visibilitas target
Visibilitas target mengontrol siapa yang mungkin bergantung pada target Anda — yaitu, siapa yang dapat menggunakan label target dalam atribut seperti deps
.
A
target terlihat oleh B
target jika berada dalam paket yang sama, atau jika
A
memberikan visibilitas ke paket B
. Dengan demikian, 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 memberikan visibilitas ke sebuah paket tidak dengan sendirinya memberikan visibilitas ke sub-paketnya. Untuk detail selengkapnya tentang paket dan sub-paket, lihat Konsep dan terminologi.
Untuk pembuatan prototipe, Anda dapat menonaktifkan penerapan visibilitas target dengan menyetel flag --check_visibility=false
. Hal 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 dan cara
menentukan visibilitas target.
Spesifikasi visibilitas
Semua target aturan memiliki atribut visibility
yang menggunakan daftar label. Setiap label memiliki salah satu bentuk berikut. Kecuali 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; 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 tidak sub-paketnya)."//foo/bar:__subpackages__"
: Memberikan akses//foo/bar
dan semua sub-paket langsung dan tidak langsungnya."//some_pkg:my_package_group"
: Memberikan akses ke semua paket yang merupakan bagian daripackage_group
tertentu.- Grup paket menggunakan
sintaksis yang berbeda untuk
menentukan paket. Dalam grup paket, formulir
"//foo/bar:__pkg__"
dan"//foo/bar:__subpackages__"
masing-masing diganti oleh"//foo/bar"
dan"//foo/bar/..."
. Demikian pula,"//visibility:public"
dan"//visibility:private"
hanya merupakan"public"
dan"private"
.
- Grup paket menggunakan
sintaksis yang berbeda untuk
menentukan paket. Dalam grup paket, formulir
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 hierarki sumber //some/package/...
, serta target yang ditentukan di //tests/BUILD
, tetapi tidak oleh target yang ditentukan di //tests/integration/BUILD
.
Praktik terbaik: Agar beberapa target terlihat oleh kumpulan
paket yang sama, gunakan package_group
, bukan mengulangi daftar di setiap
atribut visibility
target. Hal ini akan meningkatkan keterbacaan dan mencegah
daftar menjadi tidak sinkron.
Visibilitas target aturan
Visibilitas target aturan adalah:
Nilai atribut
visibility
, jika ditetapkan; atau yang lainNilai argumen
default_visibility
dari pernyataanpackage
dalam fileBUILD
target, jika deklarasi tersebut ada; atau//visibility:private
.
Praktik terbaik: Hindari menetapkan default_visibility
ke publik. Mungkin akan lebih praktis untuk membuat prototipe atau dalam codebase kecil, tetapi risiko pembuatan target publik secara tidak sengaja akan meningkat seiring dengan berkembangnya codebase. Sebaiknya
jelaskan 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 membuatnya.
Visibilitas target file sumber
Anda dapat secara eksplisit menetapkan visibilitas target file sumber dengan memanggil
exports_files
. Jika tidak ada argumen visibility
yang diteruskan ke exports_files
, visibilitas menjadi 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 tanda ini disetel, visibilitas bersifat pribadi.
Atau, perilaku lama akan berlaku: Visibilitas sama dengan
default_visibility
fileBUILD
, atau pribadi jika visibilitas default tidak ditentukan.
Jangan mengandalkan perilaku lama. Selalu tulis deklarasi exports_files
setiap kali target file sumber memerlukan visibilitas non-pribadi.
Praktik terbaik: Jika memungkinkan, pilih untuk mengekspos target aturan, bukan
file sumber. Misalnya, daripada memanggil exports_files
pada file .java
, gabungkan file dalam target java_library
nonpribadi. Umumnya, target aturan hanya boleh merujuk langsung ke 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 belum menerapkan visibilitas untuk
target config_setting
yang
direferensikan dalam kunci select()
. Ada
dua flag untuk menghapus perilaku lama ini:
--incompatible_enforce_config_setting_visibility
memungkinkan pemeriksaan visibilitas untuk target tersebut. Untuk membantu migrasi, hal ini juga menyebabkan semuaconfig_setting
yang tidak menentukanvisibility
dianggap publik (terlepas daridefault_visibility
tingkat paket).--incompatible_config_setting_private_default_visibility
menyebabkanconfig_setting
yang tidak menentukanvisibility
mematuhidefault_visibility
paket dan kembali pada visibilitas pribadi, seperti target aturan lainnya. Ini adalah tanpa pengoperasian jika--incompatible_enforce_config_setting_visibility
tidak ditetapkan.
Jangan mengandalkan perilaku lama. Setiap config_setting
yang dimaksudkan untuk
digunakan di luar paket saat ini harus memiliki visibility
eksplisit, jika
paket tersebut belum menentukan default_visibility
yang sesuai.
Visibilitas target grup paket
Target package_group
tidak memiliki atribut visibility
. Perubahan tersebut selalu
dapat dilihat 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
mungkin membuat dependensi implisit dari setiap target aturannya ke target yang dapat dieksekusi yang mewakili compiler C++.
Visibilitas dependensi implisit tersebut diperiksa dalam kaitannya 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 akan diperiksa
sesuai dengan target cc_library
.
Anda dapat mengubah perilaku ini dengan menonaktifkan
--incompatible_visibility_private_attributes_at_definition
.
Jika dinonaktifkan, dependensi implisit diperlakukan seperti dependensi lainnya.
Artinya, target yang menjadi dependensi (seperti compiler C++ kita) harus terlihat oleh setiap instance aturan. Dalam praktiknya, target biasanya harus memiliki visibilitas publik.
Jika Anda ingin membatasi penggunaan aturan ke paket tertentu, gunakan visibilitas pemuatan.
Memuat visibilitas
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 yang melindungi kode sumber yang dienkapsulasi
oleh target, visibilitas beban melindungi logika build yang dienkapsulasi oleh file
.bzl
. Misalnya, penulis file BUILD
mungkin ingin memperhitungkan beberapa definisi target berulang
ke dalam makro di file .bzl
. Tanpa perlindungan visibilitas beban, mereka mungkin mendapati makro mereka digunakan kembali oleh kolaborator lain di ruang kerja yang sama, sehingga mengubah makro akan merusak build tim lain.
Perhatikan bahwa file .bzl
mungkin memiliki atau tidak memiliki target file sumber yang sesuai.
Jika demikian, tidak ada jaminan bahwa visibilitas beban dan visibilitas
target akan bertepatan. Artinya, file BUILD
yang sama mungkin dapat memuat file .bzl
, tetapi tidak mencantumkannya dalam srcs
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 beban dengan menetapkan
--check_bzl_visibility=false
. Seperti halnya --check_visibility=false
, hal ini tidak
boleh dilakukan untuk kode yang dikirimkan.
Visibilitas beban 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
package_group
. Namun, visibility()
tidak menerima spesifikasi paket negatif.
Panggilan ke visibility()
hanya boleh terjadi sekali per file, di level teratas (bukan di dalam fungsi), dan idealnya tepat setelah pernyataan load()
.
Tidak seperti visibilitas target, visibilitas beban default selalu bersifat 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
...
Memuat praktik visibilitas
Bagian ini menjelaskan tips untuk mengelola deklarasi visibilitas beban.
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 bias yang tidak disengaja antara berbagai visibilitas
file .bzl
. Kode ini juga akan lebih mudah dibaca jika daftar clients
berukuran besar.
Visibilitas komposisi
Terkadang file .bzl
mungkin perlu terlihat oleh daftar yang diizinkan yang
terdiri dari beberapa daftar yang diizinkan yang lebih kecil. Hal ini serupa dengan bagaimana
package_group
dapat menggabungkan package_group
lain melalui
atribut includes
-nya.
Misalnya Anda menghentikan penggunaan makro yang banyak digunakan. Anda ingin agar file 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)
Menduplikasi dengan grup paket
Tidak seperti visibilitas target, Anda tidak dapat menentukan visibilitas beban dalam konteks
package_group
. Jika Anda ingin menggunakan kembali daftar yang diizinkan yang sama untuk visibilitas
target dan visibilitas beban, sebaiknya pindahkan daftar spesifikasi
paket ke file .bzl, tempat kedua jenis deklarasi dapat merujuk ke
file tersebut. Berdasarkan contoh dalam visibilitas faktor
di atas, Anda dapat menulis:
# //mylib/BUILD
load(":internal_defs", "clients")
package_group(
name = "my_pkg_grp",
packages = clients,
)
Cara ini hanya berfungsi jika daftar tidak berisi spesifikasi paket negatif.
Melindungi setiap simbol
Simbol Starlark apa pun yang namanya diawali dengan garis bawah tidak dapat dimuat dari
file lain. Hal ini memudahkan pembuatan simbol pribadi, tetapi Anda tidak
dapat membagikan simbol ini dengan sekumpulan file tepercaya yang terbatas. Di sisi lain, visibilitas pemuatan memberi Anda kontrol atas apa yang mungkin dilihat paket lain
.bzl file
, tetapi tidak memungkinkan Anda untuk mencegah pemuatan simbol yang tidak
digarisbawahi.
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 visibilitas bzl
Ada lint Buildifier
yang memberikan peringatan jika pengguna memuat file dari direktori bernama internal
atau private
, saat file pengguna tidak berada di bawah induk direktori
tersebut. Lint ini sudah ada sebelum fitur visibilitas pemuatan dan tidak diperlukan di
ruang kerja tempat file .bzl
mendeklarasikan visibilitas.