Halaman ini menjawab beberapa pertanyaan umum (FAQ) tentang dependensi eksternal di Bazel.
MODULE.bazel
Bagaimana cara membuat versi modul Bazel?
Menetapkan version
dengan direktif module
dalam arsip sumber
MODULE.bazel
dapat memiliki beberapa kekurangan dan efek samping yang tidak diinginkan jika tidak
dikelola dengan cermat:
Duplikasi: merilis versi baru modul biasanya melibatkan penambahan versi di
MODULE.bazel
dan pemberian tag pada rilis, dua langkah terpisah yang dapat tidak sinkron. Meskipun otomatisasi dapat mengurangi risiko ini, lebih sederhana dan aman untuk menghindarinya sama sekali.Ketidakkonsistenan: pengguna yang mengganti modul dengan commit tertentu menggunakan penggantian non-registry akan melihat versi yang salah. Misalnya, jika
MODULE.bazel
dalam arsip sumber menetapkanversion = "0.3.0"
, tetapi commit tambahan telah dilakukan sejak rilis tersebut, pengguna yang mengganti dengan salah satu commit tersebut akan tetap melihat0.3.0
. Pada kenyataannya, versi harus mencerminkan bahwa versi tersebut lebih baru dari rilis, misalnya0.3.1-rc1
.Masalah penggantian non-registry: menggunakan nilai placeholder dapat menyebabkan masalah saat pengguna mengganti modul dengan penggantian non-registry. Misalnya,
0.0.0
tidak diurutkan sebagai versi tertinggi, yang biasanya merupakan perilaku yang diharapkan pengguna saat melakukan penggantian non-registry.
Oleh karena itu, sebaiknya hindari menyetel versi dalam arsip sumber
MODULE.bazel
. Sebagai gantinya, tetapkan di MODULE.bazel
yang disimpan di registry
(misalnya, Bazel Central Registry), yang merupakan sumber tepercaya untuk
versi modul selama penyelesaian dependensi eksternal Bazel (lihat Bazel
registries).
Proses ini biasanya otomatis, misalnya, repositori contoh aturan rules-template
menggunakan bazel-contrib/publish-to-bcr publish.yaml GitHub Action untuk memublikasikan rilis ke BCR. Tindakan membuat patch untuk arsip
sumber MODULE.bazel
dengan versi rilis. Patch ini disimpan di registry dan diterapkan saat modul diambil selama penyelesaian dependensi eksternal Bazel.
Dengan cara ini, versi dalam rilis di registry akan disetel dengan benar ke versi yang dirilis dan dengan demikian, bazel_dep
, single_version_override
, dan multiple_version_override
akan berfungsi seperti yang diharapkan, sekaligus menghindari potensi masalah saat melakukan penggantian non-registry karena versi dalam arsip sumber akan menjadi nilai default (''
), yang akan selalu ditangani dengan benar (ini adalah nilai versi default) dan akan berperilaku seperti yang diharapkan saat mengurutkan (string kosong diperlakukan sebagai versi tertinggi).
Kapan saya harus menaikkan tingkat kompatibilitas?
compatibility_level
modul Bazel
harus di-increment dalam commit yang sama yang memperkenalkan perubahan yang tidak kompatibel dengan versi sebelumnya ("perubahan yang menyebabkan gangguan").
Namun, Bazel dapat memunculkan error jika mendeteksi bahwa versi modul yang sama dengan tingkat kompatibilitas yang berbeda ada dalam grafik dependensi yang diselesaikan. Hal ini dapat terjadi, misalnya, saat dua modul bergantung pada versi modul ketiga dengan tingkat kompatibilitas yang berbeda.
Oleh karena itu, menaikkan compatibility_level
terlalu sering dapat sangat mengganggu
dan tidak disarankan. Untuk menghindari situasi ini, compatibility_level
harus
ditambah hanya jika perubahan yang tidak kompatibel memengaruhi sebagian besar kasus penggunaan dan tidak
mudah dimigrasikan dan/atau diatasi.
Mengapa MODULE.bazel tidak mendukung load
s?
Selama penyelesaian dependensi, file MODULE.bazel dari semua dependensi eksternal yang direferensikan diambil dari registry. Pada tahap ini, arsip sumber
dependensi belum diambil; jadi jika file MODULE.bazel load
s
file lain, Bazel tidak dapat mengambil file tersebut tanpa
mengambil seluruh arsip sumber. Perhatikan bahwa file MODULE.bazel itu sendiri bersifat khusus, karena dihosting langsung di registry.
Ada beberapa kasus penggunaan yang umumnya diminati oleh orang yang meminta load
di MODULE.bazel, dan kasus tersebut dapat diselesaikan tanpa load
:
- Memastikan bahwa versi yang tercantum dalam MODULE.bazel konsisten dengan metadata build yang disimpan di tempat lain, misalnya dalam file .bzl: Hal ini dapat dicapai dengan menggunakan metode
native.module_version
dalam file .bzl yang dimuat dari file BUILD. - Membagi file MODULE.bazel yang sangat besar menjadi beberapa bagian yang dapat dikelola, terutama untuk monorepo: Modul root dapat menggunakan direktif
include
untuk membagi file MODULE.bazel-nya menjadi beberapa segmen. Karena alasan yang sama, kami tidak mengizinkanload
di file MODULE.bazel,include
tidak dapat digunakan di modul non-root. - Pengguna sistem WORKSPACE lama mungkin ingat pernah mendeklarasikan repo, lalu
segera
load
dari repo tersebut untuk melakukan logika yang kompleks. Kemampuan ini telah diganti dengan ekstensi modul.
Dapatkah saya menentukan rentang SemVer untuk bazel_dep
?
Tidak. Beberapa pengelola paket lain seperti npm dan Cargo mendukung rentang versi (secara implisit atau eksplisit), dan hal ini sering kali memerlukan pemecah batasan (membuat output lebih sulit diprediksi oleh pengguna) dan membuat resolusi versi tidak dapat direproduksi tanpa file kunci.
Bazel menggunakan Pemilihan Versi Minimal seperti Go, yang sebaliknya membuat output mudah diprediksi dan menjamin reproduksibilitas. Ini adalah kompromi yang sesuai dengan tujuan desain Bazel.
Selain itu, versi modul Bazel adalah superkumpulan SemVer, sehingga apa yang masuk akal dalam lingkungan SemVer yang ketat tidak selalu berlaku untuk versi modul Bazel.
Dapatkah saya otomatis mendapatkan versi terbaru untuk bazel_dep
?
Beberapa pengguna terkadang meminta kemampuan untuk menentukan bazel_dep(name = "foo",
version = "latest")
agar otomatis mendapatkan versi terbaru dep. Hal ini mirip dengan pertanyaan tentang rentang SemVer, dan jawabannya juga tidak.
Solusi yang direkomendasikan di sini adalah dengan menggunakan otomatisasi untuk menanganinya. Misalnya, Renovate mendukung modul Bazel.
Terkadang, pengguna yang mengajukan pertanyaan ini benar-benar mencari cara untuk melakukan iterasi dengan cepat selama pengembangan lokal. Hal ini dapat dilakukan dengan menggunakan
local_path_override
.
Mengapa ada begitu banyak use_repo
?
Penggunaan ekstensi modul dalam file MODULE.bazel terkadang disertai dengan direktif use_repo
yang besar. Misalnya, penggunaan umum ekstensi
go_deps
dari gazelle
mungkin terlihat seperti:
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//:go.mod")
use_repo(
go_deps,
"com_github_gogo_protobuf",
"com_github_golang_mock",
"com_github_golang_protobuf",
"org_golang_x_net",
... # potentially dozens of lines...
)
Perintah use_repo
yang panjang mungkin tampak berlebihan, karena informasinya
dapat dikatakan sudah ada dalam file go.mod
yang dirujuk.
Alasan Bazel memerlukan direktif use_repo
ini adalah karena Bazel menjalankan ekstensi
modul secara lambat. Artinya, ekstensi modul hanya dijalankan jika hasilnya diamati. Karena "output" ekstensi modul adalah definisi repo, artinya
kita hanya menjalankan ekstensi modul jika repo yang ditentukannya diminta (misalnya, jika @org_golang_x_net//:foo
target dibangun, dalam contoh di atas). Namun, kita tidak tahu repositori mana yang akan ditentukan oleh ekstensi modul hingga
setelah kita menjalankannya. Di sinilah arahan use_repo
berperan; pengguna dapat memberi tahu Bazel repositori mana yang diharapkan untuk dihasilkan oleh ekstensi, dan Bazel kemudian hanya akan menjalankan ekstensi saat repositori tertentu ini digunakan.
Untuk membantu mempertahankan direktif use_repo
ini, ekstensi modul dapat menampilkan
objek extension_metadata
dari fungsi implementasinya. Pengguna dapat menjalankan perintah bazel mod tidy
untuk memperbarui direktif use_repo
untuk ekstensi modul ini.
Migrasi Bzlmod
Mana yang dievaluasi terlebih dahulu, MODULE.bazel atau WORKSPACE?
Jika --enable_bzlmod
dan --enable_workspace
ditetapkan, Anda mungkin bertanya-tanya sistem mana yang dikueri terlebih dahulu. Jawaban singkatnya adalah MODULE.bazel
(Bzlmod) dievaluasi terlebih dahulu.
Jawaban panjangnya adalah "mana yang dievaluasi terlebih dahulu" bukanlah pertanyaan yang tepat untuk
diajukan; melainkan, pertanyaan yang tepat untuk diajukan adalah: dalam konteks repo dengan
nama kanonis @@foo
, apa yang dihasilkan oleh nama repo
yang tampak @bar
? Atau, apa pemetaan repo dari @@base
?
Label dengan nama repo yang jelas (satu @
di awal) dapat merujuk ke berbagai hal berdasarkan konteks yang diselesaikan. Saat Anda melihat label
@bar//:baz
dan bertanya-tanya apa yang sebenarnya ditunjuknya, Anda harus mencari tahu terlebih dahulu
apa itu repo konteks: misalnya, jika label ada dalam file BUILD yang terletak
di repo @@foo
, maka repo konteksnya adalah @@foo
.
Kemudian, bergantung pada apa yang ada di repo konteks, tabel"visibilitas repositori" dalam panduan migrasi dapat digunakan untuk mengetahui repo mana yang sebenarnya diselesaikan oleh nama yang tampak.
- Jika repo konteks adalah repo utama (
@@
):- Jika
bar
adalah nama repo yang jelas yang diperkenalkan oleh file MODULE.bazel modul root (melalui salah satu daribazel_dep
,use_repo
,module
,use_repo_rule
), maka@bar
diselesaikan ke apa yang diklaim oleh file MODULE.bazel tersebut. - Jika tidak, jika
bar
adalah repo yang ditentukan dalam WORKSPACE (yang berarti nama kanonisnya adalah@@bar
), maka@bar
akan diselesaikan ke@@bar
. - Jika tidak,
@bar
akan diselesaikan menjadi sesuatu seperti@@[unknown repo 'bar' requested from @@]
, dan pada akhirnya akan menghasilkan error.
- Jika
- Jika repo konteks adalah repo Bzlmod-world (yaitu, sesuai dengan
modul Bazel non-root, atau dihasilkan oleh ekstensi modul), maka repo tersebut
hanya akan melihat repo Bzlmod-world lainnya, dan tidak ada repo WORKSPACE-world.
- Khususnya, hal ini mencakup repositori apa pun yang diperkenalkan dalam ekstensi modul seperti
non_module_deps
di modul root, atau instansiasiuse_repo_rule
di modul root.
- Khususnya, hal ini mencakup repositori apa pun yang diperkenalkan dalam ekstensi modul seperti
- Jika repo konteks ditentukan dalam WORKSPACE:
- Pertama, periksa apakah definisi repo konteks memiliki atribut ajaib
repo_mapping
. Jika ya, lakukan pemetaan terlebih dahulu (jadi untuk repo yang ditentukan denganrepo_mapping = {"@bar": "@baz"}
, kita akan melihat@baz
di bawah). - Jika
bar
adalah nama repo yang jelas yang diperkenalkan oleh file MODULE.bazel modul root, maka@bar
akan di-resolve ke klaim file MODULE.bazel tersebut. (Ini sama dengan item 1 dalam kasus repo utama.) - Jika tidak,
@bar
akan ditetapkan ke@@bar
. Kemungkinan besar ini akan mengarah ke repobar
yang ditentukan dalam WORKSPACE; jika repo tersebut tidak ditentukan, Bazel akan menampilkan error.
- Pertama, periksa apakah definisi repo konteks memiliki atribut ajaib
Untuk versi yang lebih ringkas:
- Repositori bzlmod-world (kecuali repositori utama) hanya akan melihat repositori bzlmod-world.
- Repositori dunia WORKSPACE (termasuk repositori utama) akan terlebih dahulu melihat apa yang ditentukan oleh modul root di dunia Bzlmod, lalu kembali ke repositori dunia WORKSPACE.
Perlu diperhatikan bahwa label di command line Bazel (termasuk tanda Starlark, nilai tanda berjenis label, dan pola target build/pengujian) diperlakukan seolah-olah memiliki repo utama sebagai repo konteks.
Lainnya
Bagaimana cara menyiapkan dan menjalankan build offline?
Gunakan perintah bazel fetch
untuk melakukan pengambilan awal repo. Anda dapat menggunakan tanda --repo
(seperti bazel fetch --repo @foo
) untuk mengambil hanya @foo
repo (diselesaikan dalam
konteks repo utama, lihat pertanyaan
di atas), atau menggunakan pola
target (seperti bazel fetch @foo//:bar
) untuk mengambil semua dependensi transitif dari
@foo//:bar
(ini setara dengan bazel build --nobuild @foo//:bar
).
Untuk memastikan tidak ada pengambilan data selama build, gunakan --nofetch
. Lebih tepatnya, hal ini akan membuat setiap upaya untuk menjalankan aturan repositori non-lokal gagal.
Jika Anda ingin mengambil repo dan memodifikasinya untuk pengujian secara lokal, pertimbangkan untuk menggunakan perintah bazel vendor
.
Bagaimana cara menggunakan proxy HTTP?
Bazel mematuhi variabel lingkungan http_proxy
dan HTTPS_PROXY
yang umumnya
diterima oleh program lain, seperti
curl.
Bagaimana cara membuat Bazel lebih memilih IPv6 dalam penyiapan IPv4/IPv6 stack ganda?
Di komputer khusus IPv6, Bazel dapat mendownload dependensi tanpa perubahan. Namun,
di mesin stack ganda IPv4/IPv6, Bazel mengikuti konvensi yang sama seperti Java,
lebih memilih IPv4 jika diaktifkan. Dalam beberapa situasi, misalnya saat jaringan IPv4 tidak dapat menyelesaikan/menjangkau alamat eksternal, hal ini dapat menyebabkan pengecualian Network
unreachable
dan kegagalan build. Dalam kasus ini, Anda dapat mengganti
perilaku Bazel untuk lebih memilih IPv6 dengan menggunakan
java.net.preferIPv6Addresses=true
properti
sistem.
Khususnya:
Gunakan opsi peluncuran
--host_jvm_args=-Djava.net.preferIPv6Addresses=true
, misalnya dengan menambahkan baris berikut dalam file.bazelrc
Anda:startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true
Saat menjalankan target build Java yang perlu terhubung ke internet (seperti untuk pengujian integrasi), gunakan tanda
--jvmopt=-Djava.net.preferIPv6Addresses=true
alat. Misalnya, sertakan dalam file.bazelrc
Anda:build --jvmopt=-Djava.net.preferIPv6Addresses
Jika Anda menggunakan
rules_jvm_external
untuk penyelesaian versi dependensi, tambahkan juga-Djava.net.preferIPv6Addresses=true
ke variabel lingkunganCOURSIER_OPTS
untuk menyediakan opsi JVM untuk Coursier.
Dapatkah aturan repo dijalankan dari jarak jauh dengan eksekusi jarak jauh?
Tidak; atau setidaknya, belum. Pengguna yang menggunakan layanan eksekusi jarak jauh untuk mempercepat build mungkin menyadari bahwa aturan repo masih dijalankan secara lokal. Misalnya, http_archive
akan didownload terlebih dahulu ke komputer lokal (menggunakan cache download
lokal jika berlaku), diekstrak, lalu setiap file sumber akan diupload ke layanan
eksekusi jarak jauh sebagai file input. Wajar jika Anda bertanya
mengapa layanan eksekusi jarak jauh tidak mendownload dan mengekstrak arsip tersebut saja,
sehingga menghemat perjalanan pulang pergi yang tidak berguna.
Sebagian alasannya adalah karena aturan repo (dan ekstensi modul) mirip dengan "skrip" yang dijalankan oleh Bazel itu sendiri. Eksekutor jarak jauh tidak harus memiliki Bazel yang terinstal.
Alasan lainnya adalah Bazel sering kali memerlukan file BUILD dalam arsip yang didownload dan diekstrak untuk melakukan pemuatan dan analisis, yang dilakukan secara lokal.
Ada ide awal untuk memecahkan masalah ini dengan membayangkan ulang aturan repo sebagai
aturan build, yang secara alami akan memungkinkan aturan tersebut dijalankan dari jarak jauh, tetapi sebaliknya
menimbulkan masalah arsitektur baru (misalnya, perintah query
berpotensi perlu menjalankan tindakan, sehingga memperumit desainnya).
Untuk pembahasan sebelumnya tentang topik ini, lihat Cara mendukung repositori yang memerlukan Bazel untuk pengambilan.