Halaman ini membahas cara membuat program dengan Bazel, sintaksis perintah build, dan sintaksis pola target.
Panduan memulai
Untuk menjalankan Bazel, buka direktori workspace dasar Anda
atau subdirektorinya, lalu ketik bazel
. Lihat build jika Anda
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 pada grafik tindakan pascaanalisis.build
: Membuat target yang ditentukan.canonicalize-flags
: Melakukan kanonikalisasi flag Bazel.clean
: Menghapus file output dan secara opsional menghentikan server.cquery
: Menjalankan kueri grafik dependensi pascaanalisis.dump
: Mengeluarkan status internal proses server Bazel.help
: Mencetak bantuan untuk perintah, atau indeks.info
: Menampilkan info runtime tentang server bazel.fetch
: Mengambil semua dependensi eksternal target.mobile-install
: Menginstal aplikasi di perangkat seluler.query
: Menjalankan kueri grafik dependensi.run
: Menjalankan target yang ditentukan.shutdown
: Menghentikan server Bazel.test
: Membangun 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
menjalankan 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
Agar dapat memulai build, Anda memerlukan ruang kerja. Ruang kerja adalah hierarki direktori yang berisi semua file sumber yang diperlukan untuk membangun aplikasi Anda. Bazel memungkinkan Anda melakukan build dari volume yang sepenuhnya hanya baca.
Untuk membuat program dengan Bazel, ketik bazel build
diikuti dengan
target yang ingin Anda buat.
bazel build //foo
Setelah memberikan perintah untuk mem-build //foo
, Anda akan melihat output yang mirip 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 di grafik dependensi target Anda. Ini termasuk dependensi yang dideklarasikan, file yang tercantum langsung dalam file BUILD
target, dan dependensi transitif, file yang tercantum dalam file BUILD
dependensi target Anda. Setelah mengidentifikasi semua dependensi, Bazel menganalisisnya
kebenaran dan membuat tindakan build. Terakhir, Bazel mengeksekusi
compiler dan alat build lainnya.
Selama fase eksekusi build, Bazel akan mencetak pesan progres. Pesan progres mencakup langkah build saat ini (seperti, compiler atau linker) saat dimulai, dan angka yang selesai di atas jumlah total tindakan build. Saat build dimulai, jumlah total tindakan sering kali meningkat saat Bazel menemukan seluruh grafik tindakan, tetapi jumlahnya akan stabil dalam beberapa detik.
Pada akhir build, Bazel akan mencetak target mana yang diminta, apakah target tersebut berhasil di-build atau tidak, dan jika ya, tempat file output dapat ditemukan. Skrip yang menjalankan build dapat mengurai output ini dengan andal; lihat
--show_result
untuk mengetahui detail selengkapnya.
Jika Anda mengetik lagi perintah yang sama, build akan selesai 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
Build ini adalah null build. Karena tidak ada yang berubah, tidak ada paket untuk dimuat ulang dan tidak ada langkah build untuk dijalankan. Jika ada sesuatu yang berubah pada 'foo' atau dependensinya, Bazel akan mengeksekusi 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
akan menentukan beberapa target. Pola target adalah generalisasi sintaksis label untuk kumpulan target, menggunakan karakter pengganti. Dalam kasus yang paling sederhana, setiap
label yang valid juga merupakan pola target yang valid, yang mengidentifikasi kumpulan yang berisi tepat satu
target.
Semua pola target yang dimulai dengan //
akan diselesaikan secara 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) dalam semua paket di bawah direktori foo . |
//foo/...:all-targets |
Semua target (aturan dan file) dalam semua paket di bawah direktori foo . |
//... |
Semua target dalam paket di ruang kerja. Ini tidak termasuk target dari repositori eksternal. |
//:all |
Semua target dalam paket level atas, jika ada file `BUILD` di root ruang kerja. |
Pola target yang tidak dimulai dengan //
akan diselesaikan secara 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 rekursif, 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 pada paket, yang menunjukkan semua paket secara berulang
di bawah direktori foo
(untuk semua root jalur paket). :all
adalah
karakter pengganti dari target, yang cocok dengan semua aturan dalam paket. Keduanya dapat
digabungkan, seperti di foo/...:all
, dan jika kedua karakter pengganti digunakan, karakter pengganti 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, tempat target build seperti _deploy.jar
tidak diinginkan.
Selain itu, Bazel memungkinkan penggunaan garis miring, bukan titik dua yang diperlukan oleh
sintaksis label; hal ini biasanya memudahkan saat menggunakan perluasan nama file Bash.
Misalnya, foo/bar/wiz
setara dengan //foo/bar:wiz
(jika ada
paket foo/bar
) atau dengan //foo:bar/wiz
(jika ada paket foo
).
Banyak perintah Bazel menerima daftar pola target sebagai argumen, dan semuanya
mengikuti operator negasi awalan -
. Fungsi ini dapat digunakan untuk mengurangi kumpulan target dari kumpulan yang ditentukan oleh argumen sebelumnya. Perhatikan bahwa ini berarti
urutan itu penting. Misalnya,
bazel build foo/... bar/...
berarti "build semua target di bawah foo
dan semua target di bawah bar
", sedangkan
bazel build -- foo/... -foo/bar/...
berarti "build semua target di bawah foo
kecuali target di bawah foo/bar
". (Argumen
--
diperlukan untuk mencegah argumen berikutnya yang dimulai dengan -
diinterpretasikan sebagai opsi tambahan.)
Penting untuk diperhatikan bahwa mengurangi target dengan cara ini tidak akan menjamin bahwa target tidak dibuat, karena mungkin merupakan dependensi target yang tidak dikurangi. Misalnya, jika ada //foo:all-apis
target yang antara lain bergantung pada //foo/bar:api
, target kedua akan dibuat sebagai bagian dari pembuatan build.
Target dengan tags = ["manual"]
tidak disertakan dalam pola target karakter pengganti (...
, :*
, :all
, dll.) saat ditentukan dalam perintah seperti bazel build
dan bazel test
; Anda harus menentukan target pengujian tersebut dengan pola target eksplisit pada command line jika ingin Bazel mem-build/mengujinya. Sebaliknya, bazel query
tidak melakukan
pemfilteran seperti itu secara otomatis (yang akan menggagalkan tujuan
bazel query
).
Mengambil dependensi eksternal
Secara default, Bazel akan mendownload dan melakukan symlink dependensi eksternal selama
build. Namun, hal ini mungkin tidak diinginkan, baik karena Anda ingin mengetahui kapan dependensi eksternal baru ditambahkan atau karena Anda ingin "mengambil data" dependensi (misalnya, sebelum penerbangan saat Anda akan offline). Jika
ingin mencegah dependensi baru ditambahkan selama build, Anda
dapat menentukan flag --fetch=false
. Perhatikan bahwa flag ini hanya berlaku untuk aturan repositori yang tidak mengarah ke direktori dalam sistem file lokal. Perubahan, misalnya, pada local_repository
,
new_local_repository
serta aturan repositori Android SDK dan NDK
akan selalu diterapkan 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
tidak mengizinkan pengambilan selama build, Anda harus menjalankan bazel fetch
:
- Sebelum Anda membangun untuk pertama kalinya.
- Setelah Anda menambahkan dependensi eksternal baru.
Setelah dijalankan, Anda tidak perlu menjalankannya lagi sampai file WORKSPACE berubah.
fetch
mengambil daftar target untuk mengambil dependensi. Misalnya, tindakan 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 sama sekali tidak perlu menjalankan pengambilan bazel jika memiliki semua alat yang
digunakan (dari jar library hingga JDK itu sendiri) pada root ruang kerja.
Namun, jika Anda menggunakan apa pun 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 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 diinstal.
Entri diambil dari cache jika
Bazel mengetahui dengan pasti bahwa entri tersebut memiliki salinan file yang benar, yaitu, jika
permintaan download memiliki jumlah SHA256 dari file yang ditentukan dan file dengan hash tersebut
ada di dalam cache. Jadi, menentukan hash untuk setiap file eksternal
bukan hanya merupakan ide yang bagus 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 dalam direktori cache dapat dengan mudah ditentukan, misalnya untuk membersihkan cache secara manual. Cache tidak pernah dibersihkan secara otomatis, karena mungkin berisi salinan file yang tidak lagi tersedia di upstream.
Direktori file distribusi
Direktori distribusi adalah mekanisme Bazel lain 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, selain itu hash file tersebut
sama dengan yang ditentukan dalam permintaan download. Opsi ini hanya berfungsi jika hash file ditentukan dalam deklarasi WORKSPACE.
Meskipun kondisi pada nama file tidak diperlukan untuk ketepatan, kondisi ini mengurangi jumlah file kandidat menjadi satu per direktori yang ditentukan. Dengan cara ini, penetapan direktori file distribusi akan tetap efisien, meskipun jumlah file dalam direktori tersebut semakin besar.
Menjalankan Bazel di lingkungan dengan air gap
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 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 di lingkungan dengan airgap, meskipun Anda telah mem-vendor semua dependensi WORKSPACE Anda. Untuk mengatasinya, Anda dapat menyiapkan direktori distribusi yang berisi dependensi ini di mesin yang memiliki akses jaringan, lalu mentransfernya ke lingkungan airgap 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 airgapped, terlebih dahulu periksa 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 khusus tersebut:
bazel build @additional_distfiles//:archives.tar
Ekspor tarball ini ke direktori yang dapat disalin ke lingkungan airgapped Anda. Perhatikan flag --strip-components
, karena --distdir
bisa
cukup rumit dengan tingkat tingkatan direktori:
tar xvf bazel-bin/external/additional_distfiles/archives.tar \
-C "$NEW_DIRECTORY" --strip-components=3
Terakhir, saat Anda menggunakan Bazel di lingkungan dengan airgap, teruskan flag --distdir
yang menunjuk ke direktori. 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 yang berbeda. Jenis pertama adalah informasi
intrinsik yang disimpan dalam file BUILD
project Anda: aturan build, nilai atributnya, dan set lengkap dependensi transitifnya.
Jenis kedua adalah data eksternal atau lingkungan, yang disediakan oleh pengguna atau
oleh alat build: pilihan arsitektur target, opsi kompilasi dan penautan, serta opsi konfigurasi toolchain lainnya. Kami menyebut satu set lengkap data lingkungan sebagai konfigurasi.
Dalam setiap build yang diberikan, mungkin terdapat lebih dari satu konfigurasi. Pertimbangkan
kompilasi silang, tempat Anda mem-build file //foo:bin
yang dapat dieksekusi untuk arsitektur
64-bit, tetapi workstation Anda adalah mesin 32-bit. Jelas, build akan
memerlukan build //foo:bin
menggunakan toolchain yang mampu membuat file 64-bit
yang dapat dieksekusi, tetapi sistem build juga harus mem-build berbagai alat yang digunakan selama
build itu sendiri—misalnya alat yang di-build dari sumber, lalu kemudian
digunakan dalam, misalnya, genrule—dan ini harus di-build untuk berjalan di workstation Anda. Dengan demikian, kita dapat mengidentifikasi dua konfigurasi: konfigurasi host, yang digunakan untuk membuat alat yang berjalan selama build, dan konfigurasi target (atau konfigurasi permintaan, tetapi kita lebih sering mengatakan "konfigurasi target" meskipun kata tersebut sudah memiliki banyak arti), yang digunakan untuk membuat biner yang pada akhirnya Anda minta.
Biasanya, ada banyak library yang merupakan prasyarat dari target build yang diminta (//foo:bin
) dan satu atau beberapa alat host, misalnya beberapa library dasar. Library tersebut harus dibuat dua kali, sekali untuk konfigurasi
host, dan sekali untuk konfigurasi target. Bazel memastikan
bahwa kedua varian telah di-build, dan file turunan disimpan terpisah
untuk menghindari gangguan; biasanya target tersebut dapat dibuat secara bersamaan,
karena mereka tidak bergantung satu sama lain. Jika Anda melihat pesan progres
yang menunjukkan bahwa target tertentu sedang di-build dua kali, kemungkinan besar
ini adalah penjelasannya.
Bazel menggunakan salah satu dari dua cara untuk memilih konfigurasi host, berdasarkan
opsi --distinct_host_configuration
. Opsi boolean ini kurang begitu kentara, dan setelannya dapat meningkatkan (atau memperburuk) kecepatan build Anda.
--distinct_host_configuration=false
Jika opsi ini disetel ke salah, konfigurasi host dan permintaan akan identik: semua alat yang diperlukan selama build akan dibuat dengan cara yang sama persis seperti program target. Setelan ini berarti bahwa tidak ada library yang perlu di-build dua kali selama satu build.
Namun, hal ini berarti bahwa setiap perubahan pada konfigurasi permintaan Anda juga akan memengaruhi konfigurasi host Anda, sehingga menyebabkan semua alat di-build ulang, dan apa pun yang bergantung pada output alat akan dibuat ulang juga. Jadi, misalnya, hanya mengubah opsi penaut antar-build dapat menyebabkan semua alat ditautkan ulang, lalu semua tindakan yang menggunakannya akan dieksekusi ulang, dan seterusnya, sehingga menghasilkan build ulang yang sangat besar.
--distinct_host_configuration=true
(default)
Jika opsi ini bernilai benar, maka konfigurasi host yang benar-benar berbeda akan digunakan, dan bukan menggunakan konfigurasi yang sama untuk host dan permintaan. Konfigurasi host diambil dari konfigurasi target sebagai berikut:
- Gunakan versi Crosstool yang sama (
--crosstool_top
) 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 host. - Gunakan nilai
--host_javabase
untuk--javabase
- Gunakan nilai
--host_java_toolchain
untuk--java_toolchain
- Gunakan build yang dioptimalkan untuk kode C++ (
-c opt
). - Tidak ada 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, yang berbeda dengan yang digunakan oleh konfigurasi permintaan yang memungkinkan.
- Menyembunyikan stempel biner dengan data build (lihat opsi
--embed_*
). - Semua nilai lainnya tetap pada nilai defaultnya.
Ada banyak alasan mengapa lebih baik memilih konfigurasi host yang berbeda dari konfigurasi permintaan. Beberapa di antaranya terlalu khusus untuk disebutkan di sini, tetapi dua di antaranya layak untuk disebutkan.
Pertama, dengan menggunakan biner yang dihapus dan dioptimalkan, Anda mengurangi waktu yang dihabiskan untuk menautkan dan menjalankan alat, ruang disk yang digunakan oleh alat, dan waktu I/O jaringan dalam build terdistribusi.
Kedua, dengan memisahkan konfigurasi host dan permintaan di semua build, Anda akan menghindari build ulang yang sangat mahal yang akan dihasilkan dari perubahan kecil pada konfigurasi permintaan (seperti mengubah opsi linker), seperti yang dijelaskan sebelumnya.
Meskipun demikian, untuk build tertentu, opsi ini mungkin merupakan hambatan. Secara khusus, build dengan perubahan konfigurasi yang jarang terjadi (terutama build Java tertentu), dan build yang jumlah kode yang harus dibuat dalam konfigurasi host dan target besar, mungkin tidak bermanfaat.
Memperbaiki build ulang inkremental
Salah satu tujuan utama project Bazel adalah memastikan build ulang inkremental yang benar. Alat build sebelumnya, terutama yang didasarkan pada Make, membuat beberapa asumsi yang tidak wajar dalam implementasi build inkremental.
Pertama, stempel waktu file meningkat secara monoton. Meskipun hal ini biasanya terjadi, sangat mudah untuk melanggar asumsi ini; menyinkronkan ke revisi file sebelumnya menyebabkan waktu modifikasi file berkurang; Sistem berbasis Make tidak akan di-build ulang.
Secara lebih umum, meskipun Make mendeteksi perubahan pada file, fitur ini tidak mendeteksi perubahan
pada perintah. Jika Anda mengubah opsi yang diteruskan ke compiler dalam langkah build tertentu, Make tidak akan menjalankan ulang compiler, dan Anda perlu menghapus output tidak valid dari build sebelumnya secara manual menggunakan make clean
.
Selain itu, Make tidak andal terhadap kegagalan penghentian salah satu subprosesnya setelah subproses tersebut mulai menulis ke file output-nya. Meskipun eksekusi Make saat ini akan gagal, pemanggilan Make selanjutnya akan dengan tidak memahaminya menganggap bahwa file output yang terpotong tersebut valid (karena lebih baru daripada inputnya), dan tidak akan dibuat ulang. Demikian pula, jika proses {i>Make<i} dihentikan, situasi serupa dapat terjadi.
Bazel menghindari asumsi ini, dan lain-lain. Bazel mempertahankan database dari semua pekerjaan yang telah dilakukan sebelumnya, dan hanya akan menghilangkan langkah build jika menemukan bahwa kumpulan 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 (dan 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 bagi pengguna build inkremental yang benar adalah: lebih sedikit waktu yang terbuang karena kebingungan. (Selain itu, lebih sedikit waktu yang diperlukan untuk menunggu build ulang yang disebabkan oleh penggunaan make
clean
, baik diperlukan maupun preemtif.)
Membangun konsistensi dan build inkremental
Secara formal, kami menentukan status build sebagai konsisten jika semua file output yang diharapkan ada, dan isinya benar, seperti yang ditentukan oleh langkah-langkah atau aturan yang diperlukan untuk membuatnya. Saat Anda mengedit file sumber, status build dikatakan tidak konsisten, dan tetap tidak konsisten hingga Anda menjalankan fitur build lagi hingga berhasil diselesaikan. Kami menjelaskan situasi ini sebagai inkonsistensi yang tidak stabil, karena hanya bersifat sementara, dan konsistensi dapat dipulihkan dengan menjalankan alat build.
Ada jenis inkonsistensi lain yang berbahaya: inkonsistensi
stabil. Jika build mencapai status tidak konsisten yang stabil, pemanggilan alat build yang berhasil berulang
tidak akan memulihkan konsistensi: build
telah "terhenti", dan output-nya tetap salah. Status tidak konsisten stabil
adalah alasan utama pengguna Make (dan alat build lainnya) jenis make clean
.
Menemukan bahwa alat build telah gagal dengan cara ini (lalu memulihkannya
dari alat tersebut) bisa memakan waktu dan sangat menjengkelkan.
Secara konseptual, cara paling sederhana untuk mencapai build yang konsisten adalah dengan membuang semua output build sebelumnya dan memulai lagi: membuat setiap build menjadi build yang bersih. Pendekatan ini jelas terlalu menyita waktu untuk menjadi praktis (kecuali mungkin bagi engineer rilis), sehingga alat build harus dapat menjalankan build inkremental tanpa mengorbankan konsistensi.
Analisis dependensi inkremental yang benar sulit dilakukan, dan seperti yang dijelaskan di atas, banyak alat build lain yang berfungsi dengan buruk dalam menghindari status tidak konsisten yang stabil selama build inkremental. Sebaliknya, Bazel menawarkan jaminan berikut: setelah pemanggilan alat build berhasil dan Anda tidak melakukan pengeditan, build akan berada dalam status konsisten. (Jika Anda mengedit file sumber selama build, Bazel tidak menjamin konsistensi hasil build saat ini. Namun, hal tersebut menjamin bahwa hasil build next akan memulihkan konsistensi.)
Seperti semua jaminan, terdapat beberapa cetak kecil: ada beberapa cara yang diketahui 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. Namun, kami akan menyelidiki dan melakukan yang terbaik untuk memperbaiki semua status tidak konsisten yang stabil yang timbul dari penggunaan alat build yang normal atau "wajar".
Jika Anda pernah mendeteksi status yang tidak konsisten dengan Bazel, laporkan bug.
Eksekusi dengan sandbox
Bazel menggunakan sandbox untuk menjamin bahwa tindakan berjalan secara hermetis dan
benar. Bazel menjalankan spawns (secara longgar: tindakan) di sandbox yang hanya berisi kumpulan file minimal yang diperlukan alat untuk melakukan tugasnya. Saat ini,
sandbox berfungsi di Linux 3.12 atau yang lebih baru dengan opsi CONFIG_USER_NS
yang diaktifkan, dan juga di macOS 10.11 atau yang lebih baru.
Bazel akan mencetak peringatan jika sistem Anda tidak mendukung sandbox untuk memberi tahu
Anda bahwa build tidak dijamin bersifat hermetic 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. Gejalanya biasanya berupa 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 mana yang Anda gunakan agar kami dapat
menyelidiki dan memberikan perbaikan dalam rilis berikutnya.
Fase build
Di Bazel, build terjadi dalam tiga fase yang berbeda; sebagai pengguna, memahami perbedaan di antara keduanya akan memberikan insight tentang opsi yang mengontrol build (lihat di bawah).
Memuat fase
Yang pertama adalah memuat saat semua file BUILD yang diperlukan untuk target awal, dan penutupan dependensi transitifnya, akan dimuat, diurai, dievaluasi, dan di-cache.
Untuk build pertama setelah server Bazel dimulai, fase pemuatan biasanya memerlukan waktu beberapa detik lebih banyak file BUILD yang dimuat 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, kesalahan leksik dan tata bahasa dalam file BUILD, serta error evaluasi.
Fase analisis
Fase kedua, analisis, melibatkan analisis semantik dan validasi setiap aturan build, konstruksi grafik dependensi build, dan penentuan pekerjaan apa yang harus dilakukan di setiap langkah build.
Seperti pemuatan, analisis juga memerlukan waktu beberapa detik jika dihitung secara keseluruhan. Namun, Bazel menyimpan grafik dependensi dalam cache dari satu build ke build berikutnya dan hanya menganalisis ulang yang diperlukannya, sehingga build inkremental menjadi sangat cepat jika paket tidak berubah sejak build sebelumnya.
Error yang dilaporkan pada tahap ini mencakup: dependensi yang tidak sesuai, input yang tidak valid ke aturan, dan semua pesan error khusus aturan.
Fase pemuatan dan analisis berjalan cepat karena Bazel menghindari I/O file yang tidak diperlukan pada tahap ini, sehingga hanya membaca file BUILD untuk menentukan pekerjaan yang akan dilakukan. Hal ini sudah dirancang, dan menjadikan Bazel sebagai fondasi 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 output dari setiap langkah dalam build konsisten dengan inputnya, menjalankan kembali alat kompilasi/penautan/dll. jika diperlukan. Pada langkah inilah build menghabiskan sebagian besar waktunya, mulai dari beberapa detik hingga lebih dari satu jam untuk build besar. Error yang dilaporkan selama fase ini mencakup: file sumber tidak ada, error dalam alat yang dijalankan oleh beberapa tindakan build, atau kegagalan alat untuk menghasilkan kumpulan output yang diharapkan.