Modul Bazel

Laporkan masalah Lihat sumber Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Modul Bazel adalah project Bazel yang dapat memiliki beberapa versi, yang masing-masing memublikasikan metadata tentang modul lain yang menjadi dependensinya. Hal ini mirip dengan konsep yang sudah 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 (di samping file WORKSPACE). File ini adalah manifes modul, yang menyatakan 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 perintah yang tersedia dalam file MODULE.bazel.

Untuk melakukan penyelesaian modul, Bazel dimulai dengan membaca file MODULE.bazel modul root, lalu berulang kali meminta file MODULE.bazel dependensi 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 dengan registry lagi 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 terkenal 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" dari versi harus terdiri dari 3 segmen: MAJOR.MINOR.PATCH. Di Bazel, persyaratan ini dilonggarkan sehingga jumlah segmen apa pun diizinkan.
  • Dalam SemVer, setiap segmen di bagian "rilis" hanya boleh berupa digit. Di Bazel, hal ini dilonggarkan untuk mengizinkan huruf juga, dan semantik perbandingan cocok dengan "identifier" di bagian "pra-rilis".
  • Selain itu, semantik peningkatan versi utama, minor, dan 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 dibandingkan a < b jika dan hanya jika hal yang sama berlaku saat keduanya dibandingkan sebagai versi modul Bazel.

Pemilihan versi

Pertimbangkan masalah dependensi berlian, yang merupakan hal pokok dalam ruang pengelolaan dependensi yang diberi 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 dengan versi sebelumnya, sehingga memilih versi tertinggi yang ditentukan oleh dependensi apa pun (D 1.1 dalam contoh kita). Versi ini disebut "minimal" karena D 1.1 adalah versi paling awal yang dapat memenuhi persyaratan kami. Meskipun ada D 1.2 atau yang lebih baru, kami tidak akan memilihnya. Penggunaan MVS membuat proses pemilihan versi yang berfidelitas tinggi dan dapat direproduksi.

Versi yang dibatalkan

Registry dapat menyatakan versi tertentu sebagai dibatalkan jika versi tersebut harus dihindari (seperti karena kerentanan keamanan). Bazel akan menampilkan error saat memilih versi modul yang dibatalkan. Untuk memperbaiki error ini, upgrade ke versi yang lebih baru dan tidak dibatalkan, atau gunakan flag --allow_yanked_versions untuk mengizinkan versi yang dibatalkan secara eksplisit.

Tingkat kompatibilitas

Di Go, asumsi MVS tentang kompatibilitas dengan versi sebelumnya berfungsi karena MVS memperlakukan versi modul yang tidak kompatibel dengan versi sebelumnya sebagai modul terpisah. Dari segi SemVer, artinya A 1.x dan A 2.x dianggap sebagai modul yang berbeda, dan dapat berada bersama dalam grafik dependensi yang di-resolve. 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 dengan versi sebelumnya. Nomor ini disebut tingkat kompatibilitas, dan ditentukan oleh setiap versi modul dalam direktif module()-nya. 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 dilakukan untuk dependensi transitif yang tidak bergantung langsung pada modul root.

Penggantian versi tunggal

single_version_override memenuhi 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 serangkaian patch untuk diterapkan ke modul yang didownload.

Semua atribut ini bersifat opsional dan dapat digabungkan satu sama lain.

Penggantian beberapa versi

multiple_version_override dapat ditentukan untuk memungkinkan beberapa versi modul yang sama berada bersama dalam grafik dependensi yang di-resolve.

Anda dapat menentukan daftar eksplisit versi yang diizinkan untuk modul, yang semuanya harus ada dalam grafik dependensi sebelum penyelesaian — harus ada beberapa dependensi transitif yang bergantung pada setiap versi yang diizinkan. Setelah penyelesaian, 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 di grafik dependensi sebelum penyelesaian dan versi utama adalah tingkat kompatibilitas:

  • Penggantian beberapa versi yang memungkinkan 1.3, 1.7, dan 2.0 menghasilkan 1.1 yang diupgrade ke 1.3, 1.5 yang diupgrade ke 1.7, dan versi lainnya tetap sama.
  • Penggantian beberapa versi yang memungkinkan 1.5 dan 2.0 menghasilkan error, karena 1.7 tidak memiliki versi yang lebih tinggi pada tingkat kompatibilitas yang sama untuk diupgrade.
  • Penggantian beberapa versi yang memungkinkan 1.9 dan 2.0 akan menghasilkan error, karena 1.9 tidak ada dalam grafik dependensi sebelum penyelesaian.

Selain itu, pengguna juga dapat mengganti registri menggunakan atribut registry, seperti halnya penggantian versi tunggal.

Penggantian non-registry

Penggantian non-registry akan menghapus modul sepenuhnya dari penyelesaian versi. Bazel tidak meminta file MODULE.bazel ini dari registry, tetapi 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 merepresentasikan modul Bazel lainnya. Terkadang ada kebutuhan untuk menentukan repo yang tidak merepresentasikan modul Bazel; misalnya, repo yang berisi file JSON biasa yang akan dibaca sebagai data.

Dalam hal ini, Anda dapat menggunakan direktif use_repo_rule untuk menentukan repo secara langsung dengan memanggil aturan repo. Repositori 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 repositori dengan lebih fleksibel.

Nama repositori dan deps ketat

Nama yang terlihat dari repo yang mendukung modul ke dependen langsungnya secara default adalah nama modulnya, kecuali jika atribut repo_name dari direktif bazel_dep menyatakan sebaliknya. Perhatikan bahwa ini berarti modul hanya dapat menemukan dependensi langsungnya. Hal ini membantu mencegah kerusakan 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 hardcode nama kanonis, gunakan cara yang didukung untuk mendapatkannya langsung dari Bazel: * Dalam file BUILD dan .bzl, gunakan Label.repo_name pada instance Label yang dibuat dari string label yang diberikan oleh nama repositori 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}/runfiles atau, untuk ruleset rules_foo, di @rules_foo//foo/runfiles. * Saat berinteraksi dengan Bazel dari alat eksternal seperti IDE atau server bahasa, gunakan perintah bazel mod dump_repo_mapping untuk mendapatkan pemetaan dari nama yang terlihat ke nama kanonis untuk sekumpulan repositori tertentu.

Ekstensi modul juga dapat memperkenalkan repositori tambahan ke dalam cakupan modul yang terlihat.