Halaman ini menjawab beberapa pertanyaan umum 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.bazeldan pemberian tag pada rilis, dua langkah terpisah yang dapat tidak sinkron. Meskipun otomatisasi dapat mengurangi risiko ini, lebih mudah 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.bazeldalam 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 tersebut 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.0tidak diurutkan sebagai versi tertinggi, yang biasanya merupakan perilaku yang diharapkan pengguna saat melakukan penggantian non-registry.
Oleh karena itu, sebaiknya hindari menetapkan versi dalam arsip sumber MODULE.bazel. Sebagai gantinya, tetapkan di MODULE.bazel yang disimpan di registry
(misalnya, Bazel Central Registry), yang merupakan sumber kebenaran sebenarnya untuk
versi modul selama resolusi dependensi eksternal Bazel (lihat Registry
Bazel).
Hal ini biasanya otomatis, misalnya repositori aturan contoh rules-template menggunakan bazel-contrib/publish-to-bcr publish.yaml Tindakan GitHub untuk memublikasikan rilis ke BCR. Tindakan ini menghasilkan patch untuk sumber
arsip MODULE.bazel dengan versi rilis. Patch ini disimpan di registry dan diterapkan saat modul diambil selama resolusi dependensi eksternal Bazel.
Dengan cara ini, versi dalam rilis di registry akan ditetapkan dengan benar ke
versi yang dirilis, sehingga 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 (versi ini adalah nilai versi default) dan akan berperilaku seperti yang
diharapkan saat diurutkan (string kosong diperlakukan sebagai versi tertinggi).
Kapan saya harus menambah tingkat kompatibilitas?
compatibility_level modul Bazel
harus ditambah dalam commit yang sama yang memperkenalkan perubahan yang tidak kompatibel dengan versi sebelumnya ("breaking").
Namun, Bazel dapat menampilkan error jika mendeteksi bahwa versi modul yang sama dengan tingkat kompatibilitas yang berbeda ada dalam grafik dependensi yang diselesaikan. Hal ini dapat terjadi jika, misalnya, dua modul bergantung pada versi modul ketiga dengan tingkat kompatibilitas yang berbeda.
Oleh karena itu, menambah compatibility_level terlalu sering dapat sangat mengganggu dan tidak disarankan. Untuk menghindari situasi ini, compatibility_level harus ditambah hanya jika perubahan yang tidak kompatibel dengan versi sebelumnya memengaruhi sebagian besar kasus penggunaan dan tidak mudah dimigrasikan dan/atau diatasi.
Mengapa MODULE.bazel tidak mendukung load?
Selama resolusi 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 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 di MODULE.bazel konsisten dengan build
metadata yang disimpan di tempat lain, misalnya dalam file .bzl: Hal ini dapat dicapai
dengan menggunakan metode
native.module_versiondalam 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
includedirektif untuk membagi file MODULE.bazel menjadi beberapa segmen. Karena alasan yang sama, kami tidak mengizinkanloaddalam file MODULE.bazel,includetidak dapat digunakan dalam modul non-root. - Pengguna sistem WORKSPACE lama mungkin ingat mendeklarasikan repo, lalu segera
loaddari 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 bagi pengguna) dan membuat resolusi versi tidak dapat direproduksi tanpa file kunci.
Bazel menggunakan Minimal Version Selection seperti Go, yang sebaliknya membuat output mudah diprediksi dan menjamin kemampuan reproduksi. Hal ini merupakan kompromi yang sesuai dengan tujuan desain Bazel.
Selain itu, versi modul Bazel adalah superset dari SemVer, sehingga hal 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 menggunakan otomatisasi. Misalnya, Renovate mendukung modul Bazel.
Terkadang, pengguna yang mengajukan pertanyaan ini sebenarnya mencari cara untuk melakukan iterasi dengan cepat selama pengembangan lokal. Hal ini dapat dicapai dengan menggunakan a
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...
)
Direktif use_repo yang panjang mungkin tampak berlebihan, karena informasi tersebut dapat dikatakan sudah ada dalam file go.mod yang direferensikan.
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 target @org_golang_x_net//:foo dibuat, dalam contoh di atas). Namun, kita tidak tahu repo mana yang akan ditentukan oleh ekstensi modul hingga setelah kita menjalankannya. Di sinilah direktif use_repo berperan; pengguna dapat memberi tahu Bazel repo mana yang diharapkan akan dibuat oleh ekstensi, dan Bazel kemudian hanya akan menjalankan ekstensi saat repo 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, wajar jika Anda bertanya-tanya sistem mana yang dikonsultasikan 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 diselesaikan oleh nama repo yang
tampak @bar? Atau, apa pemetaan repo @@base?
Label dengan nama repo yang tampak (satu @ di awal) dapat merujuk ke hal yang berbeda berdasarkan konteks tempat label tersebut diselesaikan. Saat Anda melihat label @bar//:baz dan bertanya-tanya ke mana sebenarnya label tersebut mengarah, Anda harus terlebih dahulu mengetahui repo konteksnya: misalnya, jika label berada dalam file BUILD yang terletak di repo @@foo, repo konteksnya adalah @@foo.
Kemudian, bergantung pada repo konteksnya, 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
baradalah nama repo yang tampak yang diperkenalkan oleh file MODULE.bazel modul root (melalui salah satu daribazel_dep,use_repo,module,use_repo_rule), maka@barakan diselesaikan ke apa yang diklaim oleh file MODULE.bazel tersebut. - Jika tidak, jika
baradalah repo yang ditentukan di WORKSPACE (yang berarti nama kanonisnya adalah@@bar), maka@barakan diselesaikan ke@@bar. - Jika tidak,
@barakan diselesaikan ke sesuatu seperti@@[unknown repo 'bar' requested from @@], dan hal ini 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), repo tersebut hanya akan melihat repo Bzlmod-world lainnya, dan tidak ada repo WORKSPACE-world.
- Khususnya, hal ini mencakup repo apa pun yang diperkenalkan dalam ekstensi modul seperti
non_module_depsdi modul root, atau instansiasiuse_repo_ruledi modul root.
- Khususnya, hal ini mencakup repo apa pun yang diperkenalkan dalam ekstensi modul seperti
- Jika repo konteks ditentukan di WORKSPACE:
- Pertama, periksa apakah definisi repo konteks memiliki atribut
repo_mappingyang ajaib. Jika ya, lihat pemetaannya terlebih dahulu (jadi, untuk a repo yang ditentukan denganrepo_mapping = {"@bar": "@baz"}, kita akan melihat at@bazdi bawah). - Jika
baradalah nama repo yang tampak yang diperkenalkan oleh file MODULE.bazel modul root,@barakan diselesaikan ke apa yang diklaim oleh file MODULE.bazel tersebut. (Hal ini sama dengan item 1 dalam kasus repo utama.) - Jika tidak,
@barakan diselesaikan ke@@bar. Hal ini kemungkinan besar akan mengarah ke repobaryang ditentukan di WORKSPACE; jika repo tersebut tidak ditentukan, Bazel akan menampilkan error.
- Pertama, periksa apakah definisi repo konteks memiliki atribut
Untuk versi yang lebih ringkas:
- Repo Bzlmod-world (tidak termasuk repo utama) hanya akan melihat repo Bzlmod-world.
- Repo WORKSPACE-world (termasuk repo utama) akan melihat terlebih dahulu apa yang ditentukan oleh modul root di dunia Bzlmod, lalu kembali melihat repo WORKSPACE-world.
Perhatikan bahwa label di command line Bazel (termasuk flag Starlark, nilai flag berjenis label, dan pola target build/pengujian) diperlakukan sebagai memiliki repo utama sebagai repo konteks.
Lainnya
Bagaimana cara menyiapkan dan menjalankan build offline?
Gunakan perintah bazel fetch untuk mengambil repo terlebih dahulu. Anda dapat menggunakan flag --repo (seperti bazel fetch --repo @foo) untuk mengambil hanya repo @foo (diselesaikan dalam konteks repo utama, lihat pertanyaan di atas), atau menggunakan pola target (seperti bazel fetch @foo//:bar) untuk mengambil semua dependensi transitif @foo//:bar (ini setara dengan bazel build --nobuild @foo//:bar).
Untuk memastikan tidak ada pengambilan yang terjadi selama build, gunakan --nofetch. Lebih tepatnya, hal ini menyebabkan kegagalan upaya untuk menjalankan aturan repositori non-lokal.
Jika Anda ingin mengambil repo dan mengubahnya untuk menguji 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 mesin khusus IPv6, Bazel dapat mendownload dependensi tanpa perubahan. Namun, di mesin IPv4/IPv6 stack ganda, Bazel mengikuti konvensi yang sama seperti Java, yang 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 properti sistem.java.net.preferIPv6Addresses=true
Khususnya:
Gunakan
--host_jvm_args=-Djava.net.preferIPv6Addresses=trueopsi startup, misalnya dengan menambahkan baris berikut dalam file.bazelrc:startup --host_jvm_args=-Djava.net.preferIPv6Addresses=trueSaat menjalankan target build Java yang perlu terhubung ke internet (seperti untuk pengujian integrasi), gunakan
--jvmopt=-Djava.net.preferIPv6Addresses=trueflag alat. Misalnya, sertakan dalam.bazelrcfile:build --jvmopt=-Djava.net.preferIPv6AddressesJika Anda menggunakan
rules_jvm_externaluntuk resolusi versi dependensi, tambahkan juga-Djava.net.preferIPv6Addresses=truekeCOURSIER_OPTSlingkungan variabel untuk memberikan 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 memperhatikan bahwa aturan repo masih dijalankan secara lokal. Misalnya, http_archive akan didownload terlebih dahulu ke mesin lokal (menggunakan cache download lokal jika berlaku), diekstrak, lalu setiap file sumber akan diupload ke layanan eksekusi jarak jauh sebagai file input. Wajar jika bertanya mengapa layanan eksekusi jarak jauh tidak mendownload dan mengekstrak arsip tersebut, sehingga menghemat perjalanan pulang pergi yang tidak berguna.
Sebagian alasannya adalah aturan repo (dan ekstensi modul) mirip dengan "skrip" yang dijalankan oleh Bazel itu sendiri. Eksekutor jarak jauh bahkan tidak harus menginstal Bazel.
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 mengatasi masalah ini dengan membayangkan kembali 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 desainnya menjadi rumit).
Untuk pembahasan sebelumnya tentang topik ini, lihat Cara mendukung repositori yang memerlukan Bazel untuk diambil.