Halaman ini membahas cara mem-build program dengan Bazel, sintaksis perintah build, dan sintaksis pola target.
Panduan memulai
Untuk menjalankan Bazel, buka direktori workspace dasar Anda
atau subdirektorinya dan ketik bazel
. Lihat build jika
perlu membuat ruang kerja baru.
bazel help
[Bazel release bazel version]
Usage: bazel command options ...
Perintah yang tersedia
analyze-profile
: Menganalisis data profil build.aquery
: Menjalankan kueri di grafik tindakan pasca-analisis.build
: Membuat target yang ditentukan.canonicalize-flags
: Melakukan kanonikalisasi tanda Bazel.clean
: Menghapus file output dan secara opsional menghentikan server.cquery
: Menjalankan kueri grafik dependensi pasca analisis.dump
: Membuang status internal proses server Bazel.help
: Mencetak bantuan untuk perintah, atau indeks.info
: Menampilkan info runtime tentang server bazel.fetch
: Mengambil semua dependensi eksternal dari target.mobile-install
: Menginstal aplikasi di perangkat seluler.query
: Menjalankan kueri grafik dependensi.run
: Menjalankan target yang ditentukan.shutdown
: Menghentikan server Bazel.test
: Membuat dan menjalankan target pengujian yang ditentukan.version
: Mencetak informasi versi untuk Bazel.
Mendapatkan bantuan
bazel help command
: Mencetak bantuan dan opsi untukcommand
.bazel help
startup_options
: Opsi untuk JVM yang menghosting Bazel.bazel help
target-syntax
: Menjelaskan sintaksis untuk menentukan target.bazel help info-keys
: Menampilkan daftar kunci yang digunakan oleh perintah info.
Alat bazel
melakukan banyak fungsi, yang disebut perintah. Yang paling sering
digunakan adalah bazel build
dan bazel test
. Anda dapat menjelajahi pesan bantuan online menggunakan bazel help
.
Membuat satu target
Sebelum dapat memulai build, Anda memerlukan ruang kerja. Ruang kerja adalah hierarki direktori yang berisi semua file sumber yang diperlukan untuk mem-build aplikasi Anda. Dengan Bazel, Anda dapat menjalankan build dari volume hanya baca.
Untuk mem-build program dengan Bazel, ketik bazel build
diikuti dengan target yang ingin Anda build.
bazel build //foo
Setelah mengeluarkan perintah untuk mem-build //foo
, Anda akan melihat output yang serupa dengan ini:
INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
bazel-bin/foo/foo
INFO: Elapsed time: 9.905s, Critical Path: 3.25s
INFO: Build completed successfully, 6 total actions
Pertama, Bazel memuat semua paket dalam grafik dependensi target. Ini mencakup dependensi yang dideklarasikan, file yang tercantum langsung dalam file BUILD
target, dan dependensi transitif, file yang tercantum dalam file BUILD
dari dependensi target Anda. Setelah mengidentifikasi semua dependensi, Bazel menganalisis
kebenaran tersebut dan membuat tindakan build. Terakhir, Bazel menjalankan compiler dan alat build lainnya.
Selama fase eksekusi build, Bazel mencetak pesan progres. Pesan progres termasuk langkah build saat ini (seperti, compiler atau linker) saat dimulai, dan angka yang diselesaikan melebihi jumlah total tindakan build. Saat build dimulai, jumlah total tindakan sering kali meningkat saat Bazel menemukan seluruh grafik tindakan, tetapi jumlahnya stabil dalam beberapa detik.
Di akhir build, Bazel akan mencetak target yang diminta, apakah berhasil atau tidak, dan jika ya, di mana file output dapat ditemukan. Skrip yang menjalankan build dapat mengurai output ini dengan andal; lihat
--show_result
untuk detail selengkapnya.
Jika Anda mengetik perintah yang sama lagi, build akan selesai jauh lebih cepat.
bazel build //foo
INFO: Analyzed target //foo:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
bazel-bin/foo/foo
INFO: Elapsed time: 0.144s, Critical Path: 0.00s
INFO: Build completed successfully, 1 total action
Ini adalah build null. Karena tidak ada yang berubah, tidak ada paket untuk dimuat ulang dan tidak ada langkah build yang perlu dijalankan. Jika ada sesuatu yang berubah dalam 'foo' atau dependensinya, Bazel akan menjalankan ulang beberapa tindakan build, atau menyelesaikan build inkremental.
Membuat beberapa target
Bazel memungkinkan sejumlah cara untuk menentukan target yang akan dibuat. Secara kolektif,
ini disebut sebagai pola target. Sintaksis ini digunakan dalam perintah seperti
build
, test
, atau query
.
Sementara label digunakan untuk menentukan target individual, seperti untuk mendeklarasikan dependensi dalam file BUILD
, pola target Bazel menentukan beberapa target. Pola target adalah generalisasi dari sintaksis label untuk kumpulan target, menggunakan karakter pengganti. Dalam kasus yang paling sederhana, label
yang valid juga merupakan pola target yang valid, yang mengidentifikasi kumpulan tepat
satu target.
Semua pola target yang dimulai dengan //
di-resolve relatif terhadap ruang kerja
saat ini.
//foo/bar:wiz |
Hanya satu target //foo/bar:wiz . |
//foo/bar |
Setara dengan //foo/bar:bar . |
//foo/bar:all |
Semua target aturan dalam paket foo/bar . |
//foo/... |
Semua target aturan di semua paket di bawah direktori foo . |
//foo/...:all |
Semua target aturan di semua paket di bawah direktori foo . |
//foo/...:* |
Semua target (aturan dan file) di semua paket di bawah direktori foo . |
//foo/...:all-targets |
Semua target (aturan dan file) di semua paket di bawah direktori foo . |
//... |
Semua target dalam paket di ruang kerja. Ini tidak mencakup target dari repositori eksternal. |
//:all |
Semua target dalam paket level teratas, jika ada file `BUILD` di root ruang kerja. |
Pola target yang tidak dimulai dengan //
diselesaikan relatif terhadap direktori kerja saat ini. Contoh ini mengasumsikan direktori kerja foo
:
:foo |
Setara dengan //foo:foo . |
bar:wiz |
Setara dengan //foo/bar:wiz . |
bar/wiz |
Setara dengan:
|
bar:all |
Setara dengan //foo/bar:all . |
:all |
Setara dengan //foo:all . |
...:all |
Setara dengan //foo/...:all . |
... |
Setara dengan //foo/...:all . |
bar/...:all |
Setara dengan //foo/bar/...:all . |
Secara default, symlink direktori diikuti untuk pola target berulang, kecuali yang mengarah ke bawah basis output, seperti symlink praktis yang dibuat di direktori utama ruang kerja.
Selain itu, Bazel tidak mengikuti symlink saat mengevaluasi pola target
rekursif di direktori apa pun yang berisi file bernama sebagai berikut:
DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN
foo/...
adalah karakter pengganti atas package, yang menunjukkan semua paket secara rekursif
di bawah direktori foo
(untuk semua root jalur paket). :all
adalah
karakter pengganti di atas target, yang cocok dengan semua aturan dalam paket. Keduanya dapat
digabungkan, seperti dalam foo/...:all
, dan jika kedua karakter pengganti digunakan, ini dapat
disingkat menjadi foo/...
.
Selain itu, :*
(atau :all-targets
) adalah karakter pengganti yang cocok dengan setiap target
dalam paket yang cocok, termasuk file yang biasanya tidak dibuat oleh aturan apa pun,
seperti file _deploy.jar
yang terkait dengan aturan java_binary
.
Ini menyiratkan bahwa :*
menunjukkan superset dari :all
; meskipun berpotensi
membingungkan, sintaksis ini memungkinkan karakter pengganti :all
yang sudah dikenal digunakan untuk
build standar, yang tidak diinginkan oleh target build seperti _deploy.jar
.
Selain itu, Bazel memungkinkan garis miring digunakan sebagai pengganti titik dua yang diperlukan oleh
sintaksis label; hal ini sering kali praktis saat menggunakan perluasan nama file Bash.
Misalnya, foo/bar/wiz
setara dengan //foo/bar:wiz
(jika ada
paket foo/bar
) atau //foo:bar/wiz
(jika ada paket foo
).
Banyak perintah Bazel yang menerima daftar pola target sebagai argumen, dan semuanya
menerima operator negasi awalan -
. Jenis ini dapat digunakan untuk mengurangi kumpulan target dari kumpulan yang ditentukan oleh argumen sebelumnya. Perlu diperhatikan bahwa ini berarti pesanan penting. Misalnya,
bazel build foo/... bar/...
berarti "membuat semua target di bawah foo
dan semua target di bawah bar
", sedangkan
bazel build -- foo/... -foo/bar/...
berarti "buat semua target di bawah foo
kecuali yang di bawah foo/bar
". (Argumen --
diperlukan untuk mencegah argumen berikutnya yang dimulai dengan -
diinterpretasikan sebagai opsi tambahan.)
Penting untuk ditunjukkan bahwa mengurangi target dengan cara ini tidak akan menjamin bahwa target tersebut tidak dibuat, karena mungkin merupakan dependensi target yang tidak dikurangkan. Misalnya, jika ada //foo:all-apis
target yang
antara lain bergantung pada //foo/bar:api
, maka class yang kedua akan dibuat sebagai
bagian dari mem-build build pertama.
Target dengan tags = ["manual"]
tidak disertakan dalam pola target karakter pengganti (...
, :*
, :all
, dll.) jika ditentukan dalam perintah seperti bazel build
dan bazel test
(tetapi keduanya disertakan dalam pola target karakter pengganti negatif, yaitu yang akan dikurangkan). Anda harus
menentukan target pengujian tersebut dengan pola target eksplisit pada command line jika
Anda ingin Bazel mem-build/mengujinya. Sebaliknya, bazel query
tidak melakukan
pemfilteran tersebut secara otomatis (yang akan mengalahkan tujuan
bazel query
).
Mengambil dependensi eksternal
Secara default, Bazel akan mendownload dan symlink dependensi eksternal selama
build. Namun, hal ini tidak diinginkan karena Anda ingin mengetahui kapan dependensi eksternal baru ditambahkan atau karena Anda ingin "mengambil data" dependensi (misalnya, sebelum penerbangan yang akan Anda gunakan sebagai offline). Jika ingin mencegah dependensi baru ditambahkan selama proses build, Anda dapat menentukan flag --fetch=false
. Perhatikan bahwa tanda ini hanya
berlaku untuk aturan repositori yang tidak mengarah ke direktori di sistem
file lokal. Misalnya, perubahan pada local_repository
, new_local_repository
, serta aturan repositori Android SDK dan NDK
akan selalu berlaku terlepas dari nilai --fetch
.
Jika Anda melarang pengambilan selama build dan Bazel menemukan dependensi eksternal baru, build Anda akan gagal.
Anda dapat mengambil dependensi secara manual dengan menjalankan bazel fetch
. Jika
Anda tidak mengizinkan pengambilan selama proses build, Anda harus menjalankan bazel fetch
:
- Sebelum Anda mem-build untuk pertama kalinya.
- Setelah Anda menambahkan dependensi eksternal baru.
Setelah dijalankan, Anda tidak perlu menjalankannya lagi hingga file WORKSPACE berubah.
fetch
mengambil daftar target yang akan diambil dependensinya. Misalnya, Ini akan mengambil dependensi yang diperlukan untuk mem-build //foo:bar
dan //bar:baz
:
bazel fetch //foo:bar //bar:baz
Untuk mengambil semua dependensi eksternal untuk ruang kerja, jalankan:
bazel fetch //...
Anda tidak perlu menjalankan pengambilan bazel sama sekali jika Anda memiliki semua alat
yang digunakan (dari library jar ke JDK itu sendiri) di bagian root workspace.
Namun, jika Anda menggunakan sesuatu di luar direktori ruang kerja, Bazel akan otomatis menjalankan bazel fetch
sebelum menjalankan bazel build
.
Cache repositori
Bazel mencoba menghindari pengambilan file yang sama beberapa kali, meskipun file yang sama
diperlukan di ruang kerja yang berbeda, atau jika definisi repositori
eksternal berubah, tetapi masih memerlukan file yang sama untuk didownload. Untuk melakukannya,
bazel akan meng-cache semua file yang didownload dalam cache repositori, yang secara default
berada di ~/.cache/bazel/_bazel_$USER/cache/repos/v1/
. Lokasi
dapat diubah dengan opsi --repository_cache
. Cache dibagikan antara semua ruang kerja dan versi bazel yang terinstal.
Entri diambil dari cache jika
Bazel mengetahui dengan pasti bahwa file tersebut memiliki salinan file yang benar, yaitu, jika
permintaan download memiliki jumlah SHA256 dari file yang ditentukan dan file dengan
hash tersebut berada dalam cache. Jadi, menentukan hash untuk setiap file eksternal
tidak hanya baik dari perspektif keamanan, tetapi juga membantu menghindari
download yang tidak perlu.
Setelah setiap cache ditemukan, waktu modifikasi file dalam cache akan diperbarui. Dengan cara ini, penggunaan terakhir file di direktori cache dapat dengan mudah ditentukan, misalnya untuk membersihkan cache secara manual. Cache tidak pernah dibersihkan secara otomatis karena dapat berisi salinan file yang tidak lagi tersedia di upstream.
Direktori file distribusi
Direktori distribusi adalah mekanisme Bazel lainnya untuk menghindari download yang tidak perlu. Bazel menelusuri direktori distribusi sebelum cache repositori. Perbedaan utamanya adalah direktori distribusi memerlukan persiapan manual.
Dengan opsi
--distdir=/path/to-directory
,
Anda dapat menentukan direktori hanya baca tambahan untuk mencari file,
bukan mengambilnya. File diambil dari direktori tersebut jika nama file
sama dengan nama dasar URL dan juga hash file tersebut
sama dengan yang ditentukan dalam permintaan download. Proses ini hanya berfungsi jika hash file ditentukan dalam deklarasi WORKSPACE.
Meskipun kondisi pada nama file tidak diperlukan untuk kebenaran, kondisi ini mengurangi jumlah file kandidat menjadi satu file per direktori yang ditentukan. Dengan cara ini, penentuan direktori file distribusi akan tetap efisien, meskipun jumlah file dalam direktori tersebut bertambah besar.
Menjalankan Bazel di lingkungan yang memiliki celah udara
Agar ukuran biner Bazel tetap kecil, dependensi implisit Bazel diambil melalui jaringan saat berjalan untuk pertama kalinya. Dependensi implisit ini berisi toolchain dan aturan yang mungkin tidak diperlukan untuk semua orang. Misalnya, alat Android tidak dipaketkan dan diambil hanya saat mem-build project Android.
Namun, dependensi implisit ini dapat menyebabkan masalah saat menjalankan Bazel dalam lingkungan yang memiliki celah udara, meskipun Anda telah membuat vendor semua dependensi WORKSPACE Anda. Untuk mengatasi hal tersebut, Anda dapat menyiapkan direktori distribusi yang berisi dependensi ini pada mesin dengan akses jaringan, lalu mentransfernya ke lingkungan yang bermasalah dengan pendekatan offline.
Untuk menyiapkan direktori distribusi, gunakan flag
--distdir
. Anda harus melakukan ini sekali untuk setiap versi biner Bazel baru, karena dependensi implisit dapat berbeda untuk setiap rilis.
Untuk mem-build dependensi ini di luar lingkungan yang bermasalah, periksa terlebih dahulu hierarki sumber Bazel di versi yang tepat:
git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"
cd "$BAZEL_DIR"
git checkout "$BAZEL_VERSION"
Kemudian, build tarball yang berisi dependensi runtime implisit untuk versi Bazel tertentu tersebut:
bazel build @additional_distfiles//:archives.tar
Ekspor tarball ini ke direktori yang dapat disalin ke lingkungan hemat data. Perhatikan flag --strip-components
, karena --distdir
bisa sangat rumit dengan tingkat hierarki direktori:
tar xvf bazel-bin/external/additional_distfiles/archives.tar \
-C "$NEW_DIRECTORY" --strip-components=3
Terakhir, saat Anda menggunakan Bazel di lingkungan celah udara, teruskan flag --distdir
yang mengarah ke direktori tersebut. Untuk memudahkan, Anda dapat menambahkannya sebagai entri
.bazelrc
:
build --distdir=path/to/directory
Konfigurasi build dan kompilasi silang
Semua input yang menentukan perilaku dan hasil build tertentu dapat dibagi menjadi dua kategori berbeda. Jenis pertama adalah informasi
intrinsik yang disimpan dalam file BUILD
project Anda: aturan build, nilai atributnya, dan kumpulan lengkap dependensi transitifnya.
Jenis kedua adalah data eksternal atau lingkungan, yang disediakan oleh pengguna atau
oleh alat build: pilihan arsitektur target, kompilasi dan opsi
penautan, serta opsi konfigurasi toolchain lainnya. Kami menyebut kumpulan lengkap data lingkungan sebagai konfigurasi.
Pada build tertentu, mungkin ada lebih dari satu konfigurasi. Pertimbangkan
kompilasi silang, tempat Anda membuat file yang dapat dieksekusi //foo:bin
untuk arsitektur
64-bit, tetapi workstation Anda adalah mesin 32-bit. Jelas, build akan
memerlukan build //foo:bin
menggunakan toolchain yang mampu membuat file yang dapat dieksekusi
64-bit, tetapi sistem build juga harus mem-build berbagai alat yang digunakan selama
build itu sendiri—misalnya alat yang di-build dari sumber, lalu
digunakan di, misalnya, genrule—dan ini harus di-build untuk dijalankan di workstation Anda. Dengan demikian,
kita dapat mengidentifikasi dua konfigurasi: konfigurasi eksekutif, yang digunakan
untuk mem-build alat yang berjalan selama build, dan konfigurasi target
(atau konfigurasi permintaan, tetapi kita mengatakan "konfigurasi target" lebih sering meskipun
kata tersebut sudah memiliki banyak arti), yang digunakan untuk membuat
biner yang pada akhirnya Anda minta.
Biasanya, ada banyak library yang merupakan prasyarat target build
yang diminta (//foo:bin
) dan satu atau beberapa alat eksekutif, misalnya beberapa
library dasar. Library tersebut harus di-build dua kali, sekali untuk konfigurasi
eksekutif, dan sekali untuk konfigurasi target. Bazel menangani untuk memastikan bahwa kedua varian dibuat, dan file turunan disimpan terpisah untuk menghindari interferensi; biasanya target tersebut dapat dibuat secara serentak, karena keduanya tidak saling bergantung. Jika Anda melihat pesan progres
yang menunjukkan bahwa target tertentu sedang dibuat dua kali, kemungkinan besar ini
adalah penjelasan.
Konfigurasi exec berasal dari konfigurasi target sebagai berikut:
- Menggunakan versi Crosstool (
--crosstool_top
) yang sama seperti yang ditentukan dalam konfigurasi permintaan, kecuali jika--host_crosstool_top
ditentukan. - Gunakan nilai
--host_cpu
untuk--cpu
(default:k8
). - Gunakan nilai yang sama dari opsi ini seperti yang ditentukan dalam konfigurasi
permintaan:
--compiler
,--use_ijars
, dan jika--host_crosstool_top
digunakan, nilai--host_cpu
akan digunakan untuk mencaridefault_toolchain
di Crosstool (mengabaikan--compiler
) untuk konfigurasi eksekutif. - Gunakan nilai
--host_javabase
untuk--javabase
- Gunakan nilai
--host_java_toolchain
untuk--java_toolchain
- Menggunakan build yang dioptimalkan untuk kode C++ (
-c opt
). - Tidak membuat informasi proses debug (
--copt=-g0
). - Menghapus informasi debug dari file yang dapat dieksekusi dan library bersama
(
--strip=always
). - Tempatkan semua file turunan di lokasi khusus, berbeda dari yang digunakan oleh konfigurasi permintaan yang memungkinkan.
- Menyembunyikan stempel biner dengan data build (lihat opsi
--embed_*
). - Semua nilai lainnya tetap default.
Ada banyak alasan mengapa lebih baik memilih konfigurasi eksekutif yang berbeda dari konfigurasi permintaan. Yang paling penting:
Pertama, dengan menggunakan biner yang dihilangkan dan dioptimalkan, Anda akan mengurangi waktu yang dihabiskan untuk menautkan dan mengeksekusi alat, ruang disk yang ditempati oleh alat, dan waktu I/O jaringan dalam build yang terdistribusi.
Kedua, dengan memisahkan eksekusi dan konfigurasi permintaan di semua build, Anda akan menghindari build ulang yang sangat mahal yang akan diakibatkan oleh perubahan kecil pada konfigurasi permintaan (seperti mengubah opsi penaut), seperti yang dijelaskan sebelumnya.
Rekonstruksi inkremental yang benar
Salah satu sasaran utama project Bazel adalah memastikan build ulang inkremental yang benar. Alat build sebelumnya, terutama yang berdasarkan Make, membuat beberapa asumsi yang tidak terdengar dalam penerapan build inkremental mereka.
Pertama, stempel waktu file tersebut meningkat secara monoton. Meskipun ini adalah kasus biasa, sangat mudah untuk mengabaikan asumsi ini; menyinkronkan ke revisi awal file menyebabkan waktu modifikasi file tersebut berkurang; Sistem berbasis merek tidak akan mem-build ulang.
Secara lebih umum, meskipun mendeteksi perubahan pada file, Make tidak mendeteksi perubahan pada
perintah. Jika Anda mengubah opsi yang diteruskan ke compiler dalam langkah build tertentu, Make tidak akan menjalankan kembali compiler tersebut, dan Anda harus menghapus output tidak valid dari build sebelumnya secara manual menggunakan make clean
.
Selain itu, Make tidak kuat menghentikan penghentian salah satu subprosesnya setelah subproses tersebut mulai menulis ke file outputnya. Meskipun eksekusi Make saat ini akan gagal, pemanggilan Make berikutnya akan membutuhkan bahwa file output yang terpotong valid (karena lebih baru dari inputnya), dan tidak akan dibuat ulang. Demikian pula, jika proses Make dihentikan, situasi serupa dapat terjadi.
Bazel menghindari asumsi tersebut dan yang lainnya. Bazel mempertahankan database dari semua pekerjaan yang telah dilakukan sebelumnya, dan hanya akan menghapus langkah build jika menemukan bahwa sekumpulan file input (dan stempel waktunya) ke langkah build tersebut, dan perintah kompilasi untuk langkah build tersebut, sama persis dengan yang ada di database, dan, bahwa kumpulan file output (beserta stempel waktunya) untuk entri database sama persis dengan stempel waktu file di disk. Setiap perubahan pada file input atau file output, atau pada perintah itu sendiri, akan menyebabkan eksekusi ulang langkah build.
Manfaat dari pengguna build inkremental yang benar adalah: mengurangi waktu yang dihabiskan karena
kebingungan. (Selain itu, lebih sedikit waktu untuk menunggu build ulang yang disebabkan oleh penggunaan make
clean
, baik diperlukan atau preemtif.)
Konsistensi build dan build inkremental
Secara formal, kami menentukan status build sebagai konsisten jika semua file output yang diharapkan ada, dan kontennya benar, seperti yang ditentukan oleh langkah-langkah atau aturan yang diperlukan untuk membuatnya. Saat Anda mengedit file sumber, status build disebut tidak konsisten, dan tetap tidak konsisten hingga Anda menjalankan alat build hingga berhasil diselesaikan. Kami mendeskripsikan situasi ini sebagai inkonsistensi yang tidak stabil, karena hanya bersifat sementara, dan konsistensi dipulihkan dengan menjalankan alat build.
Ada jenis inkonsistensi lain yang bersifat merusak: inkonsistensi
stabil. Jika build mencapai status yang tidak konsisten secara stabil, pemanggilan
alat build yang berulang tidak akan memulihkan konsistensi: build
telah "terhenti", dan output-nya tetap salah. Status tidak stabil yang stabil
adalah alasan utama pengguna Make (dan alat build lainnya) mengetik make clean
.
Mengetahui bahwa alat build gagal dengan cara ini (dan kemudian memulihkannya dari alat tersebut) dapat memakan waktu dan sangat menjengkelkan.
Secara konseptual, cara paling sederhana untuk mencapai build yang konsisten adalah dengan menghapus semua output build sebelumnya dan memulai lagi: membuat setiap build menjadi bersih. Pendekatan ini jelas terlalu memakan waktu untuk bersifat praktis (kecuali mungkin bagi engineer rilis), sehingga alat build harus dapat melakukan build inkremental tanpa mengorbankan konsistensi.
Analisis dependensi inkremental yang benar sulit, dan seperti yang dijelaskan di atas, banyak alat build lainnya melakukan pekerjaan yang buruk untuk menghindari status tidak stabil yang stabil selama build inkremental. Sebaliknya, Bazel menawarkan jaminan berikut: setelah pemanggilan alat build berhasil dilakukan, tanpa perubahan, build akan dalam keadaan konsisten. (Jika Anda mengedit file sumber selama build, Bazel tidak akan memberikan jaminan tentang konsistensi hasil build saat ini. Namun, metode ini menjamin bahwa hasil build berikutnya akan memulihkan konsistensi.)
Seperti semua jaminan, ada beberapa persyaratan: ada beberapa cara umum untuk mendapatkan status tidak konsisten yang stabil dengan Bazel. Kami tidak akan menjamin untuk menyelidiki masalah yang timbul dari upaya yang disengaja untuk menemukan bug dalam analisis dependensi inkremental, tetapi kami akan menyelidiki dan melakukan yang terbaik untuk memperbaiki semua status tidak konsisten yang stabil yang timbul dari penggunaan alat build normal atau "wajar".
Jika Anda mendeteksi status tidak stabil yang stabil dengan Bazel, harap laporkan bug.
Eksekusi dengan sandbox
Bazel menggunakan sandbox untuk menjamin bahwa tindakan berjalan secara hermetis dan
benar. Bazel menjalankan spawns (secara longgar: tindakan) dalam sandbox yang hanya berisi kumpulan file minimal yang diperlukan alat untuk melakukan tugasnya. Sandbox
saat ini berfungsi di Linux 3.12 atau yang lebih baru dengan opsi CONFIG_USER_NS
diaktifkan, dan juga di macOS 10.11 atau yang lebih baru.
Bazel akan mencetak peringatan jika sistem Anda tidak mendukung sandbox untuk memperingatkan Anda tentang fakta bahwa build tidak dijamin akan berfungsi dan dapat memengaruhi
sistem host dengan cara yang tidak diketahui. Untuk menonaktifkan peringatan ini, Anda dapat meneruskan flag --ignore_unsupported_sandboxing
ke Bazel.
Pada beberapa platform, seperti node cluster Google Kubernetes Engine atau Debian, namespace pengguna dinonaktifkan secara default karena masalah keamanan. Hal ini dapat diperiksa dengan melihat file
/proc/sys/kernel/unprivileged_userns_clone
: jika ada dan berisi 0,
namespace pengguna dapat diaktifkan dengan
sudo sysctl kernel.unprivileged_userns_clone=1
.
Dalam beberapa kasus, sandbox Bazel gagal menjalankan aturan karena penyiapan
sistem. Gejala umumnya adalah kegagalan yang menghasilkan pesan yang mirip dengan
namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory
.
Dalam hal ini, coba nonaktifkan sandbox untuk genrules dengan --strategy=Genrule=standalone
, dan untuk aturan lainnya dengan --spawn_strategy=standalone
. Selain itu, laporkan bug di
issue tracker kami dan sebutkan distribusi Linux yang Anda gunakan agar dapat
diselidiki dan memberikan perbaikan dalam rilis berikutnya.
Fase build
Pada Bazel, build terjadi dalam tiga fase yang berbeda; sebagai pengguna, pemahaman perbedaan antara keduanya memberikan insight tentang opsi yang mengontrol build (lihat di bawah).
Fase pemuatan
Yang pertama adalah memuat selama semua file BUILD yang diperlukan untuk target awal, dan penutupan transitif dependensinya, dimuat, diuraikan, dievaluasi, dan di-cache.
Untuk build pertama setelah server Bazel dimulai, fase pemuatan biasanya membutuhkan waktu beberapa detik untuk memuat banyak file BUILD dari sistem file. Pada build berikutnya, terutama jika tidak ada file BUILD yang berubah, pemuatan akan terjadi dengan sangat cepat.
Error yang dilaporkan selama fase ini meliputi: paket tidak ditemukan, target tidak ditemukan, error leksikal dan gramatikal dalam file BUILD, dan error evaluasi.
Fase analisis
Fase kedua, analisis, melibatkan analisis semantik dan validasi setiap aturan build, konstruksi grafik dependensi build, dan penentuan dengan tepat pekerjaan yang harus dilakukan di setiap langkah build.
Seperti pemuatan, analisis juga memerlukan waktu beberapa detik saat dihitung secara keseluruhan. Namun, Bazel meng-cache grafik dependensi dari satu build ke build berikutnya dan satu-satunya menganalisis ulang apa yang harus dilakukannya, yang dapat membuat build inkremental sangat cepat jika paket belum berubah sejak build sebelumnya.
Error yang dilaporkan pada tahap ini mencakup: dependensi yang tidak pantas, input yang tidak valid untuk aturan, dan semua pesan error khusus aturan.
Fase pemuatan dan analisis berlangsung cepat karena Bazel menghindari I/O file yang tidak perlu di tahap ini, yang hanya membaca file BUILD untuk menentukan pekerjaan yang harus dilakukan. Hal ini dirancang, dan menjadikan Bazel sebagai dasar yang baik untuk alat analisis, seperti perintah query Bazel, yang diimplementasikan di atas fase pemuatan.
Fase eksekusi
Fase ketiga dan terakhir build adalah eksekusi. Fase ini memastikan bahwa output dari setiap langkah dalam build konsisten dengan inputnya, menjalankan ulang kompilasi/penautan/dll. jika diperlukan. Langkah ini adalah saat build menghabiskan sebagian besar waktunya, mulai dari beberapa detik hingga lebih dari satu jam untuk build berukuran besar. Error yang dilaporkan selama fase ini meliputi: file sumber tidak ada, error pada alat yang dijalankan oleh beberapa tindakan build, atau kegagalan alat untuk menghasilkan kumpulan output yang diharapkan.