Pertanyaan umum (FAQ)

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

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 menetapkan version = "0.3.0", tetapi commit tambahan telah dilakukan sejak rilis tersebut, pengguna yang mengganti dengan salah satu commit tersebut akan tetap melihat 0.3.0. Pada kenyataannya, versi harus mencerminkan bahwa versi tersebut lebih baru dari rilis, misalnya 0.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 loads?

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 loads 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 mengizinkan load 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 (@@):
    1. Jika bar adalah nama repo yang jelas yang diperkenalkan oleh file MODULE.bazel modul root (melalui salah satu dari bazel_dep, use_repo, module, use_repo_rule), maka @bar diselesaikan ke apa yang diklaim oleh file MODULE.bazel tersebut.
    2. Jika tidak, jika bar adalah repo yang ditentukan dalam WORKSPACE (yang berarti nama kanonisnya adalah @@bar), maka @bar akan diselesaikan ke @@bar.
    3. Jika tidak, @bar akan diselesaikan menjadi sesuatu seperti @@[unknown repo 'bar' requested from @@], dan pada akhirnya akan menghasilkan error.
  • 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 instansiasi use_repo_rule di modul root.
  • Jika repo konteks ditentukan dalam WORKSPACE:
    1. Pertama, periksa apakah definisi repo konteks memiliki atribut ajaib repo_mapping. Jika ya, lakukan pemetaan terlebih dahulu (jadi untuk repo yang ditentukan dengan repo_mapping = {"@bar": "@baz"}, kita akan melihat @baz di bawah).
    2. 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.)
    3. Jika tidak, @bar akan ditetapkan ke @@bar. Kemungkinan besar ini akan mengarah ke repo bar yang ditentukan dalam WORKSPACE; jika repo tersebut tidak ditentukan, Bazel akan menampilkan error.

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 lingkungan COURSIER_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.