Modul Bazel adalah project Bazel yang dapat memiliki beberapa versi, masing-masing yang memublikasikan metadata tentang modul lain yang menjadi dependensinya. Ini adalah analog dengan konsep yang sudah dikenal dalam sistem manajemen dependensi lainnya, seperti Artefak Maven, paket npm, modul Go, atau peti Cargo.
Modul harus memiliki file MODULE.bazel
di root repo-nya (di samping
WORKSPACE
). File ini adalah manifes modul, yang mendeklarasikan namanya,
versi, daftar dependensi langsung, dan informasi lainnya. Untuk dasar
contoh:
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 perintah yang tersedia di file MODULE.bazel
.
Untuk melakukan resolusi modul, Bazel memulai dengan membaca
MODULE.bazel
, lalu berulang kali meminta dependensi
File MODULE.bazel
dari registry Bazel hingga
menemukan seluruh grafik dependensi.
Secara default, Bazel lalu memilih satu versi dari setiap modul untuk digunakan. Bazel mewakili setiap modul dengan sebuah {i>repo<i}, dan berkonsultasi dengan {i>registry<i} lagi untuk mempelajari cara mendefinisikan masing-masing repo.
Format versi
Bazel memiliki ekosistem yang beragam dan proyek menggunakan berbagai skema pembuatan versi. Tujuan
yang paling populer sejauh ini adalah SemVer, tetapi ada
juga proyek terkemuka menggunakan berbagai skema seperti
Abseil, yang
versi berbasis tanggal, misalnya 20210324.2
).
Karena alasan ini, Bzlmod mengadopsi versi spesifikasi SemVer yang lebih longgar. Tujuan perbedaan tersebut meliputi:
- SemVer menentukan bahwa "rilis" bagian dari versi harus terdiri dari 3
segmen:
MAJOR.MINOR.PATCH
. Pada Bazel, persyaratan ini dilonggarkan sehingga jumlah segmen yang diizinkan. - Di SemVer, setiap segmen dalam "rilis" bagian harus dalam angka saja. Pada Bazel, ini dilonggarkan untuk memungkinkan huruf, dan perbandingan semantik cocok dengan "ID" dalam "prarilis" bagian.
- Selain itu, semantik peningkatan versi besar, minor, dan patch tidak diterapkan. Namun, lihat tingkat kompatibilitas untuk detail tentang bagaimana kami menunjukkan kompatibilitas mundur.
Semua 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 nilai yang sama berlaku saat
mereka dibandingkan sebagai
versi modul Bazel.
Pemilihan versi
Pertimbangkan masalah dependensi {i>diamond<i}, yang merupakan pokok dalam dependensi berversi ruang manajemen proyek. 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
Pilihan Versi Minimal
(MVS) yang diperkenalkan dalam sistem modul Go. MVS mengasumsikan bahwa semua
versi modulnya kompatibel dengan versi sebelumnya, sehingga memilih versi tertinggi
yang ditentukan oleh dependen apa pun (D 1.1
dalam contoh kita). Namanya "minimal"
karena D 1.1
adalah versi paling awal yang dapat memenuhi persyaratan kami —
meskipun ada D 1.2
atau yang lebih baru, kita tidak memilihnya. Menggunakan MVS akan membuat
proses pemilihan versi yang dengan fidelitas tinggi dan dapat direproduksi.
Versi Yanked
Registry dapat mendeklarasikan versi tertentu sebagai dicabut jika harus dihindari
(misalnya karena kerentanan keamanan). Bazel menampilkan pesan error
versi pendek dari suatu modul. Untuk memperbaiki {i>error<i} ini, upgrade ke versi yang lebih baru,
yang tidak ditarik, atau menggunakan
--allow_yanked_versions
penanda{i> <i}untuk secara eksplisit mengizinkan versi yang {i>yanked<i}.
Tingkat kompatibilitas
Di Go, asumsi MVS tentang kompatibilitas mundur berfungsi karena memperlakukan
versi modul yang tidak kompatibel dengan versi sebelumnya
sebagai modul terpisah. Dalam hal
SemVer, yang berarti A 1.x
dan A 2.x
dianggap sebagai modul yang berbeda, dan dapat
koeksistensi dalam grafik dependensi yang di-resolve. Hal ini dimungkinkan oleh
mengkodekan versi utama dalam jalur
paket di Go, sehingga tidak ada
konflik waktu kompilasi atau waktu penautan.
Namun, Bazel tidak dapat memberikan jaminan tersebut, sehingga memerlukan "versi utama"
untuk mendeteksi versi yang tidak kompatibel dengan versi sebelumnya. Nomor ini disebut
tingkat kompatibilitas, dan ditentukan oleh setiap versi modul dalam
Perintah module()
. Dengan informasi ini, Bazel dapat
memberikan {i>error<i} saat ia
mendeteksi bahwa versi modul yang sama dengan tingkat kompatibilitas yang berbeda
ada di grafik dependensi yang di-resolve.
Ganti
Menentukan penggantian di file MODULE.bazel
untuk mengubah perilaku Bazel
resolusi modul. Hanya penggantian modul {i>root<i} yang berlaku — jika modul
digunakan sebagai dependensi, penggantiannya akan diabaikan.
Setiap penggantian ditetapkan untuk nama modul tertentu, sehingga memengaruhi semua dalam grafik dependensi. Meskipun hanya penggantian modul {i> root<i} yang mengambil , bisa juga untuk dependensi transitif yang tidak dimiliki modul root bisa diandalkan secara langsung.
Penggantian versi tunggal
single_version_override
memiliki beberapa tujuan:
- Dengan atribut
version
, Anda dapat menyematkan dependensi ke terlepas dari versi dependensi mana yang diminta dalam grafik dependensi. - Dengan atribut
registry
, Anda dapat memaksa dependensi ini agar berasal dari {i>registry<i} tertentu, bukan mengikuti {i>registry<i} normal proses pemilihan. - Dengan atribut
patch*
, Anda dapat menentukan kumpulan patch yang akan diterapkan modul yang didownload.
Semua atribut ini bersifat opsional dan dapat digabungkan serta dicocokkan satu sama lain.
Penggantian beberapa versi
multiple_version_override
dapat ditentukan untuk memungkinkan beberapa versi modul yang sama hidup berdampingan dalam
menyelesaikan grafik dependensi.
Anda bisa menentukan daftar eksplisit versi yang diizinkan untuk modul, yang harus semuanya ada dalam grafik dependensi sebelum resolusi — harus ada beberapa dependensi transitif bergantung pada setiap versi yang diizinkan. Sesudah hanya versi modul yang diizinkan yang masih ada, sementara Bazel melakukan upgrade versi lain dari modul ke versi terdekat yang diizinkan lebih tinggi secara bersamaan tingkat kompatibilitas. Jika tidak ada versi lebih tinggi yang diizinkan dengan kompatibilitas yang sama Bazel akan menampilkan pesan {i>error<i}.
Misalnya, jika versi 1.1
, 1.3
, 1.5
, 1.7
, dan 2.0
ada di
grafik dependensi sebelum resolusi dan versi utamanya adalah
tingkat:
- Penggantian beberapa versi yang memungkinkan
1.3
,1.7
, dan2.0
menghasilkan1.1
sedang diupgrade ke1.3
,1.5
sedang diupgrade ke1.7
, dan versi tetap sama. - Penggantian beberapa versi yang memungkinkan
1.5
dan2.0
menghasilkan error, karena1.7
tidak memiliki versi yang lebih tinggi pada tingkat kompatibilitas yang sama untuk diupgrade. - Penggantian beberapa versi yang memungkinkan
1.9
dan2.0
menghasilkan error, karena1.9
tidak ada dalam grafik dependensi sebelum resolusi.
Selain itu, pengguna juga dapat mengganti registry menggunakan registry
, mirip dengan penggantian satu versi.
Penggantian non-registry
Penggantian non-registry sepenuhnya menghapus modul dari resolusi versi. Roti Bazel
tidak meminta file MODULE.bazel
ini dari registry, melainkan dari
repo itu sendiri.
Bazel mendukung penggantian non-registry berikut:
Menentukan repositori yang tidak merepresentasikan modul Bazel
Dengan bazel_dep
, Anda dapat menentukan repositori yang mewakili modul Bazel lainnya.
Terkadang perlu menentukan repo yang tidak mewakili Bazel
module; misalnya, file yang berisi file JSON biasa untuk dibaca sebagai data.
Dalam kasus ini, Anda dapat menggunakan use_repo_rule
untuk menentukan repositori
dengan memanggil aturan repo. Repo ini hanya akan terlihat
oleh modul tempatnya
didefinisikan.
Pada prinsipnya, konfigurasi ini diterapkan menggunakan mekanisme yang sama dengan modul ekstensi, yang memungkinkan Anda menentukan repositori dengan fleksibilitas.
Nama repositori dan dependensi ketat
Nama jelas repo yang mendukung
modul ke dependensi langsungnya secara
default adalah nama modulnya, kecuali jika
atribut repo_name
dari bazel_dep
perintah tersebut menyatakan sebaliknya. Perlu diperhatikan bahwa ini berarti modul hanya dapat menemukan
dependensi. Hal ini membantu mencegah kerusakan
yang tidak disengaja karena perubahan
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 di seluruh grafik dependensi (lihat
multiple_version_override
).
Perhatikan bahwa format nama kanonis bukanlah API yang harus Anda andalkan dan
dapat berubah kapan saja. Alih-alih melakukan {i>hard-coding<i} nama kanonis,
gunakan cara yang didukung untuk
mendapatkannya langsung dari Bazel:
* Dalam file BUILD dan .bzl
, gunakan
Label.repo_name
pada instance Label
dibuat dari string label yang diberikan oleh nama jelas repo, misalnya,
Label("@bazel_skylib").repo_name
.
* Saat mencari runfile, gunakan
$(rlocationpath ...)
atau salah satu library {i>runfile<i} di
@bazel_tools//tools/{bash,cpp,java}/runfiles
atau, untuk kumpulan aturan rules_foo
,
di @rules_foo//foo/runfiles
.
* Saat berinteraksi dengan Bazel dari alat eksternal seperti IDE atau bahasa
server, gunakan perintah bazel mod dump_repo_mapping
untuk mendapatkan pemetaan dari
nama yang jelas menjadi nama kanonis
untuk sekumpulan repositori tertentu.
Ekstensi modul juga dapat memperkenalkan repositori tambahan ke dalam cakupan modul yang terlihat.