Modul Bazel adalah project Bazel yang dapat memiliki beberapa versi, yang masing-masing memublikasikan metadata tentang modul lain yang bergantung padanya. Hal ini analog dengan konsep yang dikenal dalam sistem pengelolaan dependensi lainnya, seperti _artefak_ Maven, _paket_ npm, _modul_ Go, atau _crate_ Cargo.
Modul harus memiliki file MODULE.bazel di root repo-nya. File ini adalah manifes modul, yang mendeklarasikan nama, versi, daftar dependensi langsung, dan informasi lainnya. Untuk contoh dasar:
module(name = "my-module", version = "1.0")
bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")
Lihat daftar lengkap direktif yang tersedia dalam
MODULE.bazel file.
Untuk melakukan resolusi modul, Bazel dimulai dengan membaca file
MODULE.bazel modul root, lalu berulang kali meminta file
MODULE.bazel dependensi apa pun dari registry Bazel hingga
menemukan seluruh grafik dependensi.
Secara default, Bazel kemudian memilih satu versi setiap modul untuk digunakan. Bazel merepresentasikan setiap modul dengan repo, dan berkonsultasi lagi dengan registry untuk mempelajari cara menentukan setiap repo.
Format versi
Bazel memiliki ekosistem yang beragam dan project menggunakan berbagai skema pembuatan versi. Yang
paling populer adalah SemVer, tetapi ada
juga project terkemuka yang menggunakan skema berbeda seperti
Abseil, yang
versinya berbasis tanggal, misalnya 20210324.2).
Oleh karena itu, Bzlmod mengadopsi versi spesifikasi SemVer yang lebih fleksibel. Perbedaannya meliputi:
- SemVer menetapkan bahwa bagian "rilis" versi harus terdiri dari 3 segmen:
MAJOR.MINOR.PATCH. Di Bazel, persyaratan ini dilonggarkan sehingga memungkinkan jumlah segmen apa pun. - Di SemVer, setiap segmen di bagian "rilis" hanya boleh berupa digit. Di Bazel, hal ini dilonggarkan untuk memungkinkan huruf juga, dan semantik perbandingan cocok dengan "pengenal" di bagian "prerilis".
- Selain itu, semantik peningkatan versi utama, versi minor, dan versi patch tidak diterapkan. Namun, lihat tingkat kompatibilitas untuk mengetahui detail tentang cara kami menunjukkan kompatibilitas mundur.
Setiap versi SemVer yang valid adalah versi modul Bazel yang valid. Selain itu, dua
versi SemVer a dan b membandingkan a < b jika dan hanya jika hal yang sama berlaku saat
dibandingkan sebagai versi modul Bazel.
Pemilihan versi
Pertimbangkan masalah dependensi berlian, yang merupakan bagian penting dalam ruang pengelolaan dependensi versi. Misalkan Anda memiliki grafik dependensi:
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
Versi D mana yang harus digunakan? Untuk menjawab pertanyaan ini, Bzlmod menggunakan algoritma
Pemilihan Versi Minimal
(MVS) yang diperkenalkan dalam sistem modul Go. MVS mengasumsikan bahwa semua versi baru modul kompatibel mundur, sehingga memilih versi tertinggi yang ditentukan oleh dependensi apa pun (D 1.1 dalam contoh kami). Versi ini disebut "minimal" karena D 1.1 adalah versi paling awal yang dapat memenuhi persyaratan kami — meskipun D 1.2 atau yang lebih baru ada, kami tidak memilihnya. Menggunakan MVS akan membuat proses pemilihan versi yang berakurasi tinggi dan dapat direproduksi.
Versi yang ditarik
Registry dapat mendeklarasikan versi tertentu sebagai ditarik jika harus dihindari (seperti untuk kerentanan keamanan). Bazel menampilkan error saat memilih versi modul yang ditarik. Untuk memperbaiki error ini, upgrade ke versi yang lebih baru,
tidak ditarik, atau gunakan
--allow_yanked_versions
flag untuk secara eksplisit mengizinkan versi yang ditarik.
Tingkat kompatibilitas
Di Go, asumsi MVS tentang kompatibilitas mundur berfungsi karena memperlakukan versi modul yang tidak kompatibel mundur sebagai modul terpisah. Dalam hal SemVer, hal ini berarti A 1.x dan A 2.x dianggap sebagai modul yang berbeda, dan dapat berdampingan dalam grafik dependensi yang diselesaikan. Hal ini, pada gilirannya, dimungkinkan dengan mengenkode versi utama di jalur paket di Go, sehingga tidak ada konflik waktu kompilasi atau waktu penautan.
Namun, Bazel tidak dapat memberikan jaminan tersebut, sehingga memerlukan nomor "versi utama" untuk mendeteksi versi yang tidak kompatibel mundur. Nomor ini disebut
tingkat kompatibilitas, dan ditentukan oleh setiap versi modul dalam
module() direktifnya. Dengan informasi ini, Bazel dapat menampilkan error saat mendeteksi bahwa versi modul yang sama dengan tingkat kompatibilitas yang berbeda ada dalam grafik dependensi yang diselesaikan.
Ganti
Tentukan penggantian dalam file MODULE.bazel untuk mengubah perilaku resolusi modul Bazel. Hanya penggantian modul root yang berlaku — jika modul digunakan sebagai dependensi, penggantiannya akan diabaikan.
Setiap penggantian ditentukan untuk nama modul tertentu, yang memengaruhi semua versinya dalam grafik dependensi. Meskipun hanya penggantian modul root yang berlaku, penggantian tersebut dapat digunakan untuk dependensi transitif yang tidak bergantung langsung pada modul root.
Penggantian versi tunggal
The single_version_override
memiliki beberapa tujuan:
- Dengan atribut
version, Anda dapat menyematkan dependensi ke versi tertentu, terlepas dari versi dependensi yang diminta dalam grafik dependensi. - Dengan atribut
registry, Anda dapat memaksa dependensi ini berasal dari registry tertentu, bukan mengikuti proses pemilihan registry normal. - Dengan atribut
patch*, Anda dapat menentukan kumpulan patch yang akan diterapkan ke modul yang didownload.
Semua atribut ini bersifat opsional dan dapat digabungkan satu sama lain.
Penggantian beberapa versi
A multiple_version_override
dapat ditentukan untuk memungkinkan beberapa versi modul yang sama berdampingan dalam grafik dependensi yang diselesaikan.
Anda dapat menentukan daftar eksplisit versi yang diizinkan untuk modul, yang semuanya harus ada dalam grafik dependensi sebelum resolusi — harus ada dependensi transitif tertentu yang bergantung pada setiap versi yang diizinkan. Setelah resolusi, hanya versi modul yang diizinkan yang tetap ada, sementara Bazel mengupgrade versi modul lainnya ke versi yang diizinkan lebih tinggi terdekat pada tingkat kompatibilitas yang sama. Jika tidak ada versi yang diizinkan lebih tinggi pada tingkat kompatibilitas yang sama, Bazel akan menampilkan error.
Misalnya, jika versi 1.1, 1.3, 1.5, 1.7, dan 2.0 ada dalam grafik dependensi sebelum resolusi dan versi utama adalah tingkat kompatibilitas:
- Penggantian beberapa versi yang mengizinkan
1.3,1.7, dan2.0akan menyebabkan1.1diupgrade ke1.3,1.5diupgrade ke1.7, dan versi lainnya tetap sama. - Penggantian beberapa versi yang mengizinkan
1.5dan2.0akan menghasilkan error, karena1.7tidak memiliki versi yang lebih tinggi pada tingkat kompatibilitas yang sama untuk diupgrade. - Penggantian beberapa versi yang mengizinkan
1.9dan2.0akan menghasilkan error, karena1.9tidak ada dalam grafik dependensi sebelum resolusi.
Selain itu, pengguna juga dapat mengganti registry menggunakan atribut registry, mirip dengan penggantian versi tunggal.
Penggantian non-registry
Penggantian non-registry akan menghapus modul sepenuhnya dari resolusi versi. Bazel tidak meminta file MODULE.bazel ini dari registry, tetapi dari repo itu sendiri.
Bazel mendukung penggantian non-registry berikut:
Menentukan repo yang tidak merepresentasikan modul Bazel
Dengan bazel_dep, Anda dapat menentukan repo yang merepresentasikan modul Bazel lainnya.
Terkadang ada kebutuhan untuk menentukan repo yang tidak merepresentasikan modul Bazel; misalnya, repo yang berisi file JSON biasa untuk dibaca sebagai data.
Dalam hal ini, Anda dapat menggunakan use_repo_rule
direktif untuk menentukan repo secara langsung
dengan memanggil aturan repo. Repo ini hanya akan terlihat oleh modul tempatnya ditentukan.
Di balik layar, hal ini diimplementasikan menggunakan mekanisme yang sama dengan ekstensi modul, yang memungkinkan Anda menentukan repo dengan lebih fleksibel.
Nama repositori dan dependensi ketat
Nama tampak dari repo yang mendukung
modul ke dependensi langsungnya secara default adalah nama modulnya, kecuali jika atribut
repo_name dari direktif bazel_dep
menyatakan sebaliknya. Perhatikan bahwa hal ini berarti modul hanya dapat menemukan dependensi langsungnya. Hal ini membantu mencegah gangguan yang tidak disengaja karena perubahan pada dependensi transitif.
Nama kanonis repo yang mendukung
modul adalah module_name+version (misalnya, bazel_skylib+1.0.3) atau module_name+ (misalnya, bazel_features+), bergantung pada apakah ada
beberapa versi modul dalam seluruh grafik dependensi (lihat
multiple_version_override).
Perhatikan bahwa format nama kanonis bukanlah API yang harus Anda andalkan dan
dapat berubah kapan saja. Daripada melakukan hard code nama kanonis, gunakan cara yang didukung untuk mendapatkannya langsung dari Bazel:
- Dalam file BUILD dan
.bzl, gunakanLabel.repo_namepada instanceLabelyang dibuat dari string label yang diberikan oleh nama repo yang terlihat, misalnya,Label("@bazel_skylib").repo_name. - Saat mencari runfile, gunakan
$(rlocationpath ...)atau salah satu library runfile di@bazel_tools//tools/{bash,cpp,java}/runfilesatau, untuk rulesetrules_foo, di@rules_foo//foo/runfiles. - Saat berinteraksi dengan Bazel dari alat eksternal seperti IDE atau server bahasa, gunakan perintah
bazel mod dump_repo_mappinguntuk mendapatkan pemetaan dari nama yang terlihat ke nama kanonis untuk kumpulan repositori tertentu.
Ekstensi modul juga dapat memperkenalkan repo tambahan ke dalam cakupan modul yang terlihat.