Visibilitas

Laporkan masalah Lihat sumber Per Malam · 7,2 · 7,1 · 7,0 · 6,5 · 6,4

Halaman ini membahas dua sistem visibilitas Bazel: visibilitas target dan visibilitas pemuatan.

Kedua jenis visibilitas ini membantu developer lain membedakan antara API publik library dan detail implementasinya, serta membantu menegakkan struktur seiring dengan berkembangnya ruang kerja Anda. Anda juga dapat menggunakan visibilitas saat menghentikan penggunaan API untuk memungkinkan pengguna saat ini dan menolak pengguna baru.

Visibilitas target

Visibilitas target mengontrol siapa yang mungkin bergantung pada target Anda — yaitu, siapa yang mungkin gunakan label target di dalam atribut seperti deps.

A target terlihat oleh target B jika berada dalam paket yang sama, atau jika A memberikan visibilitas ke paket B. Jadi, paket adalah unit dari perincian untuk memutuskan apakah mengizinkan akses atau tidak. Jika B bergantung pada A tetapi A tidak terlihat oleh B, maka segala upaya untuk membangun B akan gagal selama analisis.

Perhatikan bahwa memberikan visibilitas ke paket tidak dengan sendirinya memberikan visibilitas pada 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 atribut tandai --check_visibility=false. Hal ini tidak boleh dilakukan untuk penggunaan produksi di kode yang dikirimkan.

Cara utama untuk mengontrol visibilitas adalah dengan Atribut visibility aktif 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. Masing-masing label memiliki salah satu bentuk berikut. Dengan pengecualian dalam bentuk yang terakhir, hanyalah placeholder sintaksis yang tidak sesuai dengan target aktual.

  • "//visibility:public": Memberikan akses ke semua paket. (Tidak dapat digabungkan dengan spesifikasi lainnya.)

  • "//visibility:private": Tidak memberikan akses tambahan apa pun; target saja dalam paket ini dapat menggunakan target tersebut. (Tidak dapat digabungkan dengan specification.)

  • "//foo/bar:__pkg__": Memberikan akses ke //foo/bar (tetapi tidak sub-paket).

  • "//foo/bar:__subpackages__": Memberikan akses //foo/bar dan semua aksesnya sub-paket langsung dan tidak langsung.

  • "//some_pkg:my_package_group": Memberikan akses ke semua paket yang adalah bagian dari package_group yang diberikan.

    • Grup paket menggunakan sintaksis yang berbeda untuk menentukan paket. Di dalam grup paket, formulir "//foo/bar:__pkg__" dan "//foo/bar:__subpackages__" masing-masing diganti dengan "//foo/bar" dan "//foo/bar/...". Demikian juga, "//visibility:public" dan "//visibility:private" hanya "public" dan "private".

Misalnya, jika //some/package:mytarget menetapkan visibility-nya ke [":__subpackages__", "//tests:__pkg__"], maka dapat digunakan oleh target mana pun yang merupakan bagian dari hierarki sumber //some/package/..., serta target yang ditentukan di //tests/BUILD, tetapi bukan berdasarkan target yang ditentukan dalam //tests/integration/BUILD.

Praktik terbaik: Untuk membuat beberapa target terlihat oleh kumpulan yang sama paket, gunakan package_group daripada mengulangi daftar di setiap atribut visibility target. Hal ini meningkatkan keterbacaan dan mencegah daftar agar tidak sinkron.

Visibilitas target aturan

Visibilitas target aturan:

  1. Nilai atribut visibility, jika ditetapkan; atau yang lain

  2. Nilai atribut default_visibility argumen pernyataan package di kolom file BUILD target, jika deklarasi tersebut ada; atau yang lain

  3. //visibility:private.

Praktik terbaik: Hindari menyetel default_visibility ke publik. Mungkin sangat mudah digunakan untuk pembuatan prototipe atau codebase kecil, tetapi berisiko membuat target publik akan meningkat seiring pertumbuhan codebase. Lebih baik menjadi eksplisit tentang 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 yang akan menghasilkannya.

Visibilitas target file sumber

Anda dapat secara eksplisit menetapkan visibilitas target file sumber dengan memanggil exports_files Saat tidak ada visibility diteruskan ke exports_files, sehingga visibilitas menjadi publik. exports_files tidak boleh digunakan untuk mengganti visibilitas file yang dihasilkan.

Untuk target file sumber yang tidak muncul dalam panggilan ke exports_files, visibilitas yang bergantung pada nilai flag --incompatible_no_implicit_file_export:

  • Jika tanda ini disetel, visibilitas akan disetel ke pribadi.

  • Selain itu, perilaku lama akan berlaku: Visibilitasnya sama dengan default_visibility file BUILD, atau pribadi jika visibilitas default adalah tidak ditentukan.

Hindari mengandalkan perilaku lama. Selalu tulis exports_files setiap kali target file sumber memerlukan visibilitas non-pribadi.

Praktik terbaik: Jika memungkinkan, lebih memilih untuk mengekspos target aturan, bukan file sumbernya. Misalnya, sebagai ganti memanggil exports_files di file .java, gabungkan file dalam target java_library non pribadi. Secara umum, target aturan sebaiknya hanya merujuk ke file sumber yang ada di 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

Sebelumnya, Bazel tidak menerapkan visibilitas untuk config_setting target yang yang direferensikan dalam kunci select(). Ada adalah dua tanda untuk menghapus perilaku lama ini:

  • --incompatible_enforce_config_setting_visibility memungkinkan pemeriksaan visibilitas untuk target tersebut. Untuk membantu migrasi, juga menyebabkan config_setting yang tidak menentukan visibility dianggap publik (terlepas dari default_visibility level paket).

  • --incompatible_config_setting_private_default_visibility menyebabkan config_setting yang tidak menentukan visibility untuk mematuhi default_visibility paket dan untuk penggantian pada visibilitas pribadi, cukup seperti target aturan lainnya. Tanpa pengoperasian jika --incompatible_enforce_config_setting_visibility belum disetel.

Hindari mengandalkan perilaku lama. Setiap config_setting yang ditujukan untuk digunakan di luar paket saat ini harus memiliki visibility eksplisit, jika paket belum menentukan default_visibility yang cocok.

Visibilitas target grup paket

Target package_group tidak memiliki atribut visibility. Mereka selalu terlihat oleh publik.

Visibilitas dependensi implisit

Beberapa aturan memiliki dependensi implisit — dependensi yang tidak dieja dalam file BUILD tetapi melekat pada setiap kejadian dari aturan itu. Misalnya, aturan cc_library mungkin membuat dependensi implisit dari setiap target aturannya ke target yang dapat dieksekusi yang merepresentasikan compiler C++.

Visibilitas dependensi implisit tersebut diperiksa sehubungan dengan paket yang berisi file .bzl tempat aturan (atau aspek) ditentukan. Di beberapa pada contoh ini, kompilator C++ bisa bersifat pribadi selama ia berada di ruang sebagai definisi aturan cc_library. Sebagai alternatif, jika dependensi implisit tidak terlihat dari definisi, maka diperiksa dengan 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. Ini berarti bahwa target yang diandalkan (seperti kompilator C++ kita) harus terlihat oleh setiap instance aturan. Dalam praktiknya, hal ini biasanya berarti target harus memiliki visibilitas publik.

Jika Anda ingin membatasi penggunaan aturan untuk paket tertentu, gunakan memuat visibilitas.

Muat visibilitas

Visibilitas pemuatan mengontrol apakah file .bzl dapat dimuat dari File BUILD atau .bzl di luar paket saat ini.

Dengan cara yang sama seperti visibilitas target melindungi kode sumber yang dienkapsulasi berdasarkan target, visibilitas pemuatan melindungi logika build yang dienkapsulasi oleh .bzl . Misalnya, penulis file BUILD mungkin ingin memperhitungkan beberapa pengulangan definisi target ke dalam makro dalam file .bzl. Tanpa perlindungan beban mereka mungkin menemukan bahwa makro mereka digunakan kembali oleh kolaborator lain di ruang kerja yang sama, sehingga memodifikasi makro akan menghentikan tim lain build yang berbeda.

Perhatikan bahwa file .bzl mungkin memiliki atau tidak memiliki target file sumber yang sesuai. Jika ya, tidak ada jaminan bahwa visibilitas pemuatan dan target terlihat bertepatan. Artinya, file BUILD yang sama mungkin dapat memuat .bzl file tetapi tidak mencantumkannya dalam srcs dari filegroup, atau sebaliknya. Hal ini terkadang dapat menyebabkan masalah untuk aturan yang ingin menggunakan File .bzl seperti kode sumber, misalnya 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, kode ini seharusnya tidak dilakukan untuk kode yang dikirimkan.

Visibilitas pemuatan tersedia mulai Bazel 6.0.

Mendeklarasikan visibilitas pemuatan

Untuk menyetel visibilitas pemuatan file .bzl, panggil metode Fungsi visibility() dari dalam file. Argumen untuk visibility() adalah daftar spesifikasi paket, seperti atribut packages dari package_group. Namun, visibility() tidak menerima paket negatif spesifikasi produk.

Panggilan ke visibility() hanya boleh terjadi sekali per file, di tingkat teratas (bukan di dalam fungsi), dan idealnya segera mengikuti pernyataan load().

Tidak seperti visibilitas target, visibilitas pemuatan default selalu bersifat publik. File yang tidak memanggil visibility() selalu dapat dimuat dari mana saja di Workspace. 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 pemuatan.

Mempertimbangkan visibilitas

Jika beberapa file .bzl seharusnya memiliki visibilitas yang sama, sebaiknya memasukkan spesifikasi paket mereka 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 penyimpangan yang tidak disengaja antara berbagai file .bzl visibilitas. Format ini juga lebih mudah dibaca jika daftar clients berukuran besar.

Menyusun visibilitas

Terkadang file .bzl mungkin harus terlihat oleh daftar yang diizinkan yang yang terdiri dari beberapa daftar yang diizinkan. Hal ini dapat dianalisa dengan bagaimana package_group dapat menyertakan package_group lain melalui Atribut includes.

Misalkan Anda menghentikan penggunaan makro yang banyak digunakan. Anda ingin item hanya terlihat untuk pengguna yang ada dan ke paket milik 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 grup paket

Tidak seperti visibilitas target, Anda tidak dapat mendefinisikan package_group. Jika Anda ingin menggunakan kembali daftar yang diizinkan yang sama untuk kedua target visibilitas dan beban visibilitas, sebaiknya Anda memindahkan daftar paket spesifikasi ke dalam file .bzl, di mana kedua jenis deklarasi dapat merujuk pada anotasi. Mengembangkan contoh dalam Mempertimbangkan visibilitas di atas, Anda dapat menulis:

# //mylib/BUILD

load(":internal_defs", "clients")

package_group(
    name = "my_pkg_grp",
    packages = clients,
)

Perintah ini hanya berfungsi jika daftar tidak berisi paket negatif apa pun spesifikasi produk.

Melindungi setiap simbol

Setiap simbol Starlark yang namanya diawali dengan garis bawah tidak dapat dimuat dari file lain. Hal ini memudahkan pembuatan simbol pribadi, tetapi tidak memungkinkan Anda untuk berbagi simbol-simbol ini dengan kumpulan file yang terbatas. Di sisi lain tangan, visibilitas beban memberi Anda kontrol atas apa yang mungkin dilihat oleh paket .bzl file, tetapi tidak memungkinkan Anda mencegah simbol yang tidak digarisbawahi dari sedang dimuat.

Untungnya, Anda dapat menggabungkan kedua fitur ini untuk mendapatkan kontrol yang lebih detail.

# //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-visibilitas

Ada lint Buildifier yang memberikan peringatan jika pengguna memuat file dari direktori bernama internal atau private, jika file pengguna tidak berada di bawah induknya saat ini. Lint ini mendahului fitur visibilitas pemuatan dan tidak diperlukan dalam ruang kerja tempat file .bzl mendeklarasikan visibilitas.