Membuat program dengan Bazel

Laporkan masalah Lihat sumber Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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 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 pasca-analisis.
  • 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 pasca-analisis.
  • dump: Men-dump 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 untuk command.
  • bazel helpstartup_options: Opsi untuk JVM yang menghosting Bazel.
  • bazel helptarget-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. Paling umum yang 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 direktori yang berisi semua file sumber yang diperlukan untuk membangun aplikasi. 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 bangun.

bazel build //foo

Setelah mengeluarkan perintah untuk membangun //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 dalam grafik dependensi target Anda. Ini mencakup dependensi yang dideklarasikan, file yang tercantum langsung dalam BUILD target dan dependensi transitif, yang tercantum dalam file BUILD dependensi target. Setelah mengidentifikasi semua dependensi, Bazel menganalisis semuanya demi ketepatan dan membuat tindakan build. Terakhir, Bazel menjalankan compiler dan alat build lainnya.

Selama fase eksekusi build, Bazel akan mencetak pesan progres. Pesan progres mencakup langkah build saat ini (seperti compiler atau penaut) saat dimulai, dan jumlah yang diselesaikan dari total jumlah tindakan build. Saat build dimulai, jumlah total tindakan sering kali meningkat saat Bazel menemukan seluruh grafik tindakan, tetapi jumlahnya akan stabil dalam beberapa detik.

Di akhir versi, Bazel mencetak target yang diminta, apakah apakah mereka berhasil dibangun, dan jika demikian, di mana file {i>output<i} 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 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 yang akan dimuat ulang dan tidak ada langkah build yang akan dijalankan. Jika ada yang berubah di 'foo' atau dependensinya, Bazel akan mengeksekusi ulang beberapa tindakan build, atau menyelesaikan build inkremental.

Membuat beberapa target

Bazel memungkinkan berbagai cara untuk menentukan target yang akan dibuat. Secara kolektif, hal ini dikenal sebagai pola target. Sintaksis ini digunakan dalam perintah seperti build, test, atau query.

Sedangkan label digunakan untuk menentukan target Bazel, seperti untuk mendeklarasikan dependensi dalam file BUILD, menentukan beberapa target. Pola target adalah generalisasi sintaksis label untuk set target, menggunakan karakter pengganti. Dalam kasus paling sederhana, setiap label yang valid juga merupakan pola target yang valid, yang mengidentifikasi satu set dengan tepat target.

Semua pola target yang dimulai dengan // telah diselesaikan secara relatif terhadap pola saat ini Workspace.

//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. Hal ini tidak mencakup target dari repositori eksternal.
//:all Semua target di paket level teratas, jika ada file `BUILD` di {i>root <i}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:
  • //foo/bar/wiz:wiz jika foo/bar/wiz adalah paket
  • //foo/bar:wiz jika foo/bar adalah paket
  • Jika tidak, //foo:bar/wiz
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 bagian bawah basis output, seperti symlink yang dibuat di direktori root ruang kerja.

Selain itu, Bazel tidak mengikuti symlink saat mengevaluasi pola target rekursif di direktori mana pun yang berisi file yang bernama sebagai berikut: DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN

foo/... adalah karakter pengganti untuk paket, 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 sebuah paket. Kedua karakter ini 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 di-build oleh aturan apa pun, seperti file _deploy.jar yang terkait dengan aturan java_binary.

Ini menyiratkan bahwa :* menunjukkan superset dari :all; sembari berpotensi membingungkan, sintaksis ini memungkinkan karakter pengganti :all yang sudah dikenal digunakan untuk build standar, yang tidak menginginkan build target seperti _deploy.jar.

Selain itu, Bazel memungkinkan penggunaan garis miring alih-alih tanda titik dua yang dibutuhkan oleh {i>syntax<i} labelnya; ini biasanya nyaman ketika menggunakan perluasan nama {i>Bash<i}. Misalnya, foo/bar/wiz setara dengan //foo/bar:wiz (jika ada paket foo/bar) atau ke //foo:bar/wiz (jika ada paket foo).

Banyak perintah Bazel menerima daftar pola target sebagai argumen, dan semuanya mematuhi operator negasi awalan -. Ini dapat digunakan untuk mengurangi kumpulan target dari kumpulan yang ditentukan oleh argumen sebelumnya. Perhatikan bahwa hal ini berarti urutan sangatlah penting. Misalnya,

bazel build foo/... bar/...

berarti "bangun 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 berada di bawah foo/bar". ( Argumen -- diperlukan untuk mencegah argumen berikutnya yang dimulai dengan - ditafsirkan sebagai opsi tambahan.)

Namun, perlu diperhatikan bahwa mengurangi target dengan cara ini tidak akan memastikan bahwa target tidak di-build, karena target tersebut mungkin merupakan dependensi target yang tidak dikurangi. Misalnya, jika ada target //foo:all-apis yang di antaranya bergantung pada //foo/bar:api, //foo/bar:api akan di-build sebagai bagian dari mem-build //foo:all-apis.

Target dengan tags = ["manual"] tidak disertakan dalam pola target karakter pengganti (..., :*, :all, dll.) saat ditentukan dalam perintah seperti bazel build dan bazel test (tetapi disertakan dalam pola target karakter pengganti negatif, yaitu akan dikurangkan). Anda seharusnya menentukan target pengujian tersebut dengan pola target eksplisit pada baris perintah jika Anda ingin Bazel membangun/mengujinya. Sebaliknya, bazel query tidak berperforma penyaringan apa pun secara otomatis (yang akan menggagalkan tujuan bazel query).

Mengambil dependensi eksternal

Secara default, Bazel akan mendownload dan membuat symlink dependensi eksternal selama build. Namun, hal ini tidak diinginkan, baik karena Anda ingin mengetahui saat dependensi eksternal baru ditambahkan atau karena Anda ingin "pengambilan data" dependensi (misalnya, sebelum penerbangan ketika Anda akan offline). Jika Anda ingin mencegah dependensi baru ditambahkan selama build, Anda dapat menentukan flag --fetch=false. Perhatikan bahwa tanda ini hanya berlaku untuk aturan repositori yang tidak mengarah ke direktori dalam sistem file lokal. Perubahan, misalnya, pada local_repository, new_local_repository, dan aturan repositori Android SDK dan NDK akan selalu berlaku, terlepas dari nilai --fetch.

Jika Anda tidak mengizinkan 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 hingga file WORKSPACE berubah.

fetch mengambil daftar target yang dependensinya akan diambil. Misalnya, hal 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 memiliki semua alat yang digunakan (dari jar library hingga JDK itu sendiri) di 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 berbeda diperlukan di ruang kerja yang berbeda, atau jika definisi repositori diubah tetapi masih membutuhkan file yang sama untuk diunduh. Untuk melakukannya, bazel meng-cache semua file yang didownload di cache repositori yang, secara default, berada di ~/.cache/bazel/_bazel_$USER/cache/repos/v1/. Lokasi dapat diubah dengan opsi --repository_cache. Cache dibagikan di antara semua ruang kerja dan versi bazel yang diinstal. Entri diambil dari cache jika Bazel tahu 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 ada di cache. Jadi menentukan {i>hash<i} untuk setiap file eksternal adalah tidak hanya ide yang baik dari perspektif keamanan; itu juga membantu menghindari {i>download<i} yang tidak diperlukan.

Setelah setiap hit cache, waktu modifikasi file dalam cache akan diperbarui. Dengan cara ini, penggunaan terakhir file di direktori cache dapat ditentukan dengan mudah, misalnya untuk membersihkan cache secara manual. Cache tidak pernah dibersihkan secara otomatis, karena file ini mungkin berisi salinan file yang tidak tersedia lebih lama di upstream.

Direktori file distribusi

Direktori distribusi adalah mekanisme Bazel lain untuk menghindari download. Bazel menelusuri direktori distribusi sebelum cache repositori. Perbedaan utamanya adalah bahwa direktori distribusi membutuhkan persiapan.

Menggunakan --distdir=/path/to-directory , Anda bisa menentukan direktori hanya-baca tambahan untuk mencari file alih-alih mengambilnya. File diambil dari direktori tersebut jika nama file sama dengan nama dasar URL dan selain itu hash file sama dengan yang ditentukan dalam permintaan download. Hal ini hanya berfungsi jika hash file ditentukan dalam deklarasi WORKSPACE.

Meskipun kondisi pada nama file tidak diperlukan untuk keakuratan, kondisi ini akan mengurangi jumlah file kandidat menjadi satu per direktori yang ditentukan. Dengan cara ini, menentukan direktori file distribusi tetap efisien, meskipun jumlah file dalam direktori tersebut bertambah besar.

Menjalankan Bazel di lingkungan yang terisolasi

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 oleh semua orang. Sebagai misalnya, alat Android tidak dibundel dan hanya diambil saat membangun Android project secara terprogram.

Akan tetapi, dependensi implisit ini dapat menyebabkan masalah saat dijalankan Bazel di lingkungan dengan air gap, bahkan jika Anda telah memasok semua Dependensi WORKSPACE. Untuk mengatasinya, Anda dapat menyiapkan direktori distribusi yang berisi dependensi ini pada komputer dengan akses jaringan, kemudian mentransfernya ke lingkungan dengan airgap melalui pendekatan {i>offline<i}.

Untuk menyiapkan direktori distribusi, gunakan flag --distdir. Anda perlu melakukan ini sekali untuk setiap versi biner Bazel yang baru, karena dependensi implisit bisa berbeda untuk setiap rilis.

Untuk mem-build dependensi ini di luar lingkungan airgapped, pertama-tama periksa hierarki sumber Bazel pada 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 airgapped Anda lingkungan fleksibel App Engine. Perhatikan flag --strip-components, karena --distdir dapat berupa cukup rumit dengan tingkat {i>nesting<i} direktori:

tar xvf bazel-bin/external/additional_distfiles/archives.tar \
  -C "$NEW_DIRECTORY" --strip-components=3

Terakhir, saat Anda menggunakan Bazel di lingkungan dengan airgapp, teruskan --distdir yang menunjuk 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 yang diberikan dapat berupa dibagi menjadi dua kategori berbeda. Jenis pertama adalah fungsi intrinsik informasi yang disimpan di 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, kompilasi, dan penautan dan opsi konfigurasi toolchain lainnya. Kami menyebut kumpulan lengkap data lingkungan sebagai konfigurasi.

Dalam build tertentu, mungkin ada lebih dari satu konfigurasi. Pertimbangkan melakukan kompilasi silang, tempat Anda mem-build file //foo:bin yang dapat dieksekusi untuk 64-bit tapi komputer Anda adalah komputer 32-bit. Jelas, build akan memerlukan pembuatan //foo:bin menggunakan toolchain yang mampu membuat file yang dapat dijalankan 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 kemudian digunakan dalam, misalnya, genrule—dan alat ini harus di-build untuk dijalankan di workstation Anda. Jadi kita dapat mengidentifikasi dua konfigurasi: konfigurasi exec, yang digunakan untuk membuat alat yang berjalan selama build, dan konfigurasi target (atau konfigurasi permintaan, tetapi kami lebih sering mengatakan "konfigurasi target" meskipun kata itu sudah memiliki banyak arti), yang digunakan untuk membangun biner yang akhirnya Anda minta.

Biasanya, ada banyak library yang merupakan prasyarat dari target build yang diminta (//foo:bin) dan satu atau beberapa alat eksekusi, misalnya beberapa library dasar. Library tersebut harus dibuat dua kali, sekali untuk konfigurasi exec, dan sekali untuk konfigurasi target. Bazel menangani pastikan kedua varian di-build, dan file turunan disimpan terpisah untuk menghindari interferensi; biasanya target tersebut dapat di-build secara serentak, karena 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.

Konfigurasi exec berasal dari konfigurasi target sebagai berikut:

  • Gunakan 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 permintaan konfigurasi: --compiler, --use_ijars, dan jika --host_crosstool_top adalah digunakan, maka nilai --host_cpu digunakan untuk mencari default_toolchain di Crosstool (mengabaikan --compiler) untuk exec konfigurasi Anda.
  • Gunakan nilai --host_javabase untuk --javabase
  • Gunakan nilai --host_java_toolchain untuk --java_toolchain
  • Gunakan build yang dioptimalkan untuk kode C++ (-c opt).
  • Jangan buat 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 kemungkinan konfigurasi permintaan apa pun.
  • Menyembunyikan stempel biner dengan data build (lihat opsi --embed_*).
  • Semua nilai lainnya tetap dalam setelan default.

Ada banyak alasan mengapa lebih baik untuk memilih eksekutif yang berbeda dari konfigurasi permintaan. Yang terpenting:

Pertama, dengan menggunakan biner yang dihilangkan dan dioptimalkan, Anda mengurangi waktu yang dihabiskan yang menghubungkan dan menjalankan {i>tool<i}, {i> disk space <i}yang ditempati oleh {i>tool<i} tersebut, dan waktu I/O jaringan dalam build terdistribusi.

Kedua, dengan memisahkan konfigurasi exec dan request di semua build, Anda menghindari pembangunan ulang yang sangat mahal yang akan dihasilkan dari perubahan kecil pada konfigurasi permintaan (seperti mengubah opsi penaut), seperti yang dijelaskan sebelumnya.

Memperbaiki build ulang inkremental

Salah satu sasaran utama project Bazel adalah memastikan pembuatan ulang inkremental yang benar. Alat build sebelumnya, terutama yang berbasis Make, membuat beberapa asumsi yang tidak wajar dalam implementasi build inkremental.

Pertama, stempel waktu file tersebut bertambah secara monoton. Meskipun ini adalah kasus umum, asumsi ini sangat mudah dilanggar; menyinkronkan ke revisi file sebelumnya menyebabkan waktu perubahan file tersebut berkurang; sistem berbasis Make tidak akan membangun ulang.

Secara lebih umum, meskipun Make mendeteksi perubahan pada file, Make tidak mendeteksi perubahan pada perintah. Jika Anda mengubah opsi yang diteruskan ke compiler dalam build tertentu , Make tidak akan menjalankan ulang compiler, dan harus membuang output yang tidak valid dari build sebelumnya menggunakan make clean.

Selain itu, Make tidak kuat terhadap penghentian salah satu subproses setelah subproses itu mulai menulis ke file {i>outputnya<i}-nya. Meskipun eksekusi Make saat ini akan gagal, pemanggilan Make berikutnya akan beranggapan bahwa file {i>output<i} yang terpotong valid (karena lebih baru dari input-nya), dan tidak akan dibangun ulang. Demikian pula, jika proses {i>Make<i} dimatikan, situasi serupa dapat terjadi.

Bazel menghindari asumsi ini, dan lain-lain. Bazel menyimpan {i>database<i} dari semua pekerjaan yang telah dilakukan sebelumnya, dan hanya akan menghilangkan langkah build jika menemukan file input (dan stempel waktunya) ke langkah build tersebut, dan kompilasi untuk langkah build tersebut, sama persis dengan yang ada dalam database, dan kumpulan file output (dan stempel waktunya) untuk entri database sama persis stempel waktu file pada {i>disk<i}. Setiap perubahan pada file input atau output {i>file<i}, atau ke perintah itu sendiri, akan menyebabkan eksekusi ulang langkah {i>build<i}.

Keuntungan bagi pengguna build inkremental yang benar adalah: lebih sedikit waktu yang terbuang karena kebingungan. (Selain itu, lebih sedikit waktu yang dihabiskan untuk menunggu build ulang yang disebabkan oleh penggunaan make clean, baik yang diperlukan maupun yang bersifat preventif.)

Membangun konsistensi dan build inkremental

Secara formal, kita menentukan status build sebagai konsisten jika semua elemen file {i>output<i} ada, dan isinya sudah benar, seperti yang ditentukan dalam 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 alat build berikutnya hingga berhasil diselesaikan. Kami menjelaskan situasi ini sebagai tidak stabil inkonsistensi, karena hanya bersifat sementara, dan konsistensi 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 kali tidak akan memulihkan konsistensi: build telah "macet", dan output tetap salah. Status yang tidak konsisten dan stabil adalah alasan utama pengguna Make (dan alat build lainnya) mengetik make clean. Menemukan bahwa alat build telah gagal dengan cara ini (dan kemudian memulihkan dari sana) dapat memakan waktu dan sangat membuat frustrasi.

Secara konseptual, cara termudah untuk mencapai build yang konsisten adalah dengan menghapus semua output build sebelumnya dan memulai lagi: buat setiap build menjadi build bersih. Pendekatan ini jelas terlalu memakan waktu untuk praktis (kecuali mungkin bagi engineer rilis), sehingga agar berguna, alat build harus dapat untuk menjalankan build inkremental tanpa mengorbankan konsistensi.

Analisis dependensi inkremental yang benar itu sulit, dan seperti dijelaskan di atas, banyak alat build lainnya melakukan pekerjaan yang buruk untuk menghindari status tidak konsisten yang stabil selama build inkremental. Sebaliknya, Bazel menawarkan jaminan berikut: setelah pemanggilan alat build berhasil, selama Anda tidak melakukan pengeditan, build akan berada dalam status yang konsisten. (Jika Anda mengedit file sumber selama build, Bazel tidak memberikan jaminan tentang konsistensi hasil build saat ini. Namun, hal ini menjamin bahwa hasil build berikutnya akan memulihkan konsistensi.)

Seperti halnya jaminan, ada beberapa syaratnya: ada beberapa cara dalam keadaan tidak konsisten dengan Bazel. Kami tidak dapat menjamin untuk menyelidiki masalah tersebut 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 yang normal atau "wajar".

Jika Anda mendeteksi status yang stabil dan tidak konsisten dengan Bazel, laporkan bug.

Eksekusi dengan sandbox

Bazel menggunakan sandbox untuk menjamin bahwa tindakan berjalan secara hermetis dan dengan benar. Bazel menjalankan spawns (berbicara longgar: tindakan) di sandbox yang hanya berisi serangkaian file minimal yang diperlukan alat untuk melakukan tugasnya. Saat ini, sandboxing 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 {i>sandbox<i} untuk memberi peringatan kepada Anda fakta bahwa bangunan tidak dijamin menjadi hermetik dan dapat mempengaruhi sistem {i>host<i} dengan cara yang tidak diketahui. Untuk menonaktifkan peringatan ini, Anda dapat meneruskan --ignore_unsupported_sandboxing untuk Bazel.

Di beberapa platform seperti node cluster Google Kubernetes Engine atau Debian, namespace pengguna dinonaktifkan secara default karena masalah keamanan. Ini dapat diperiksa dengan melihat file /proc/sys/kernel/unprivileged_userns_clone: jika ada dan berisi 0, maka 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. Jika demikian, coba nonaktifkan {i>sandbox<i} untuk genrules dengan --strategy=Genrule=standalone dan untuk aturan lain dengan --spawn_strategy=standalone. Selain itu, laporkan bug di issue tracker kami dan sebutkan distribusi Linux yang Anda gunakan sehingga 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 ketiga fase tersebut akan memberikan insight tentang opsi yang mengontrol build (lihat di bawah).

Fase pemuatan

Yang pertama adalah memuat di mana semua file BUILD yang diperlukan untuk target awal, dan penutupan transitif dependensinya, dimuat, diuraikan, dievaluasi, dan di-cache.

Untuk pembangunan pertama setelah server Bazel dimulai, fase pemuatan biasanya memakan waktu beberapa detik sebanyak file BUILD yang dimuat dari sistem file. Dalam build berikutnya, terutama jika tidak ada file BUILD yang berubah, pemuatan terjadi dengan sangat cepat.

Kesalahan yang dilaporkan selama fase ini meliputi: paket tidak ditemukan, target tidak ditemukan, kesalahan leksikal dan tata bahasa dalam {i>file <i}BUILD, dan kesalahan evaluasi.

Fase analisis

Fase kedua, analisis, melibatkan analisis semantik dan validasi dari setiap aturan build, konstruksi grafik dependensi build, penentuan pekerjaan apa yang harus dilakukan di setiap langkah pembangunan.

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 menganalisis ulang apa yang diperlukannya, yang dapat membuat build inkremental menjadi sangat cepat kasus di mana paket tidak berubah sejak build sebelumnya.

Error yang dilaporkan pada tahap ini mencakup: dependensi yang tidak sesuai, error tidak valid input ke aturan, dan semua pesan error khusus aturan.

Fase pemuatan dan analisis cepat karena Bazel menghindari {i>file<i} yang tidak perlu I/O pada tahap ini, hanya membaca {i>file BUILD<i} untuk menentukan pekerjaan yang selesai. Ini memang dirancang, dan menjadikan Bazel sebagai fondasi yang baik untuk alat analisis, seperti perintah query Bazel, yang diimplementasikan di atas halaman fase sebelumnya.

Fase eksekusi

Fase ketiga dan terakhir dari build adalah eksekusi. Fase ini memastikan bahwa output dari setiap langkah dalam build konsisten dengan inputnya, sehingga kompilasi/penautan/dll. sesuai kebutuhan. Langkah ini adalah tempat build menghabiskan sebagian besar waktunya, mulai dari beberapa detik hingga lebih dari satu jam untuk build besar. Error yang dilaporkan selama fase ini meliputi: file sumber tidak ada, error di alat yang dieksekusi oleh beberapa tindakan build, atau kegagalan alat untuk menghasilkan output yang diharapkan.