Halaman ini membahas cara membangun program dengan Bazel, membuat {i>syntax<i} perintah, dan {i>syntax<i} pola target Anda.
Panduan memulai
Untuk menjalankan Bazel, buka direktori workspace dasar Anda
atau subdirektorinya dan ketik bazel
. Lihat build jika Anda
butuhkan untuk 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
: 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 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 Bazel yang menghosting JVM.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. Paling umum
yang digunakan adalah bazel build
dan bazel test
. Anda dapat menjelajahi
bantuan online
pesan 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 untuk melakukan build dari volume.
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 eksekusi
compiler dan alat lain untuk build.
Selama fase eksekusi build, Bazel akan mencetak pesan progres. Progres pesan menyertakan langkah build saat ini (seperti, compiler atau penaut) yang dimulai, dan jumlah selesai di atas jumlah total tindakan build. Sebagai dimulainya build, jumlah total tindakan sering kali meningkat saat Bazel menemukan seluruh grafik tindakan, tetapi jumlahnya 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 harus dimuat ulang dan tidak ada langkah build untuk dijalankan. Jika ada perubahan di 'foo' atau dependensi, Bazel akan mengeksekusi ulang beberapa tindakan build, atau build inkremental.
Membuat beberapa target
Bazel memungkinkan berbagai cara untuk menentukan target yang akan dibuat. Secara kolektif,
hal ini dikenal sebagai pola target. Sintaks 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 dari
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 aturan dalam paket di repositori utama. Tidak menyertakan target dari repositori eksternal. |
//:all |
Semua target aturan di paket tingkat 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:
|
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 {i>default<i}, {i>symlink<i} direktori diikuti untuk pola target rekursif, kecuali yang menunjuk ke bawah basis output, seperti kemudahan symlink yang dibuat di direktori utama ruang kerja.
Selain itu, Bazel tidak mengikuti symlink saat mengevaluasi target rekursif
pola 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 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 hal ini mungkin
digabungkan, seperti di foo/...:all
, dan jika kedua karakter pengganti digunakan, keduanya dapat berupa
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 dibangun 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 satu set data
target dari kumpulan yang ditentukan oleh argumen sebelumnya. Perhatikan bahwa ini berarti
urutan itu 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.)
Penting untuk diketahui bahwa mengurangi target
dengan cara ini tidak akan
menjamin bahwa mereka tidak dibangun, karena mereka mungkin merupakan dependensi target
yang tidak dikurangkan. Misalnya, jika ada target //foo:all-apis
yang antara lain bergantung pada //foo/bar:api
, maka yang terakhir akan dibangun sebagai
membangun solusi.
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 pola tersebut akan dikurangi). 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 {i>default<i}, Bazel akan mengunduh dan
melakukan symlink dependensi eksternal selama
buat. 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 yang menyebabkan Anda offline). Jika Anda
ingin mencegah dependensi baru ditambahkan selama build, Anda
dapat menentukan flag --fetch=false
. Perhatikan bahwa penanda ini hanya
berlaku untuk aturan repositori yang tidak mengarah ke direktori dalam
sistem file. Perubahan, misalnya, menjadi local_repository
,
new_local_repository
dan aturan repositori NDK dan Android SDK
akan selalu berlaku, apa pun nilai --fetch
.
Jika Anda melarang pengambilan selama build dan Bazel menemukan eksternal baru dependensi, build Anda akan gagal.
Anda dapat mengambil dependensi secara manual dengan menjalankan bazel fetch
. Jika
Anda 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 WORKSPACE perubahan file.
fetch
mengambil daftar target yang dependensinya akan diambil. Sebagai
contoh ini akan mengambil dependensi yang diperlukan untuk membangun //foo:bar
dan //bar:baz
:
bazel fetch //foo:bar //bar:baz
Untuk mengambil semua dependensi eksternal untuk ruang kerja, jalankan:
bazel fetch //...
Dengan Bazel 7 atau yang lebih baru, jika Bzlmod diaktifkan, Anda juga dapat mengambil semua dependensi eksternal dengan menjalankan
bazel fetch
Anda tidak perlu menjalankan pengambilan {i>bazel<i} sama sekali
jika Anda sudah memiliki semua alat
(dari library jar ke JDK itu sendiri) di bawah root workspace Anda.
Namun, jika Anda menggunakan apa pun di luar direktori {i>workspace<i}, maka Bazel
akan otomatis menjalankan bazel fetch
sebelum berjalan
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,
{i>bazel cache<i} menyimpan semua file yang diunduh
di {i>cache<i} repositori yang, secara {i>default<i},
terletak di ~/.cache/bazel/_bazel_$USER/cache/repos/v1/
. Tujuan
lokasi dapat diubah dengan opsi --repository_cache
. Tujuan
cache dibagikan antara semua ruang kerja dan versi bazel yang terinstal.
Entri diambil dari cache jika
Bazel tahu pasti bahwa ia memiliki salinan file yang benar, jika
permintaan download memiliki jumlah SHA256 dari file yang ditentukan dan file dengan
{i>hash <i}ada dalam {i>cache<i}. 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 cache ditemukan, waktu modifikasi file dalam cache diperbarui. Dengan cara ini, penggunaan terakhir dari sebuah file dalam direktori {i>cache<i} dapat dengan mudah ditentukan, misalnya untuk membersihkan cache secara manual. Cache tidak pernah dibersihkan secara otomatis, karena file ini mungkin berisi salinan file yang tidak tersedia lebih lama lagi di upstream.
[Tidak digunakan lagi] Direktori file distribusi
Tidak digunakan lagi: Penggunaan cache repositori lebih disarankan untuk mencapai build offline.
Direktori distribusi adalah mekanisme Bazel lain untuk menghindari download. Bazel mencari 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 {i>hash<i} dari file adalah
sama dengan yang ditentukan
dalam permintaan download. Fungsi ini hanya berfungsi jika
yang ditentukan dalam deklarasi WORKSPACE.
Meskipun kondisi pada nama file tidak diperlukan untuk ketepatan, mengurangi jumlah file kandidat menjadi satu per direktori yang ditentukan. Di sini menentukan direktori file distribusi tetap efisien, bahkan jika jumlah file dalam direktori seperti itu menjadi 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 untuk 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 menjalankan Bazel lingkungan airgapped, bahkan jika Anda telah memasok semua eksternal Anda dependensi. Untuk mengatasinya, Anda dapat menyiapkan cache repositori (dengan Bazel 7 atau yang lebih baru) atau direktori distribusi (dengan Bazel sebelum 7) yang berisi dependensi pada komputer yang memiliki akses jaringan, dan kemudian mentransfernya ke dengan pendekatan offline.
Cache repositori (dengan Bazel 7 atau yang lebih baru)
Untuk menyiapkan cache repositori, gunakan
--repository_cache
penanda. Anda perlu melakukan ini sekali
untuk setiap versi biner Bazel yang baru, karena
dependensi implisit bisa
berbeda untuk setiap rilis.
Untuk mengambil dependensi tersebut di luar lingkungan airgapp Anda, buat terlebih dahulu ruang kerja kosong:
mkdir empty_workspace && cd empty_workspace
touch MODULE.bazel
touch WORKSPACE
Untuk mengambil dependensi Bzlmod bawaan, jalankan
bazel fetch --repository_cache="path/to/repository/cache"
Jika Anda masih mengandalkan file WORKSPACE lama, untuk mengambil WORKSPACE bawaan dependensi, jalankan
bazel sync --repository_cache="path/to/repository/cache"
Terakhir, saat Anda menggunakan Bazel di lingkungan dengan airgapp, teruskan
--repository_cache
. Untuk memudahkan, Anda dapat menambahkannya sebagai .bazelrc
entri:
common --repository_cache="path/to/repository/cache"
Selain itu, Anda mungkin juga perlu meng-clone
BCR secara lokal dan menggunakan
tanda --registry
untuk mengarahkan salinan lokal Anda untuk mencegah Bazel mengakses
BCR melalui internet. Tambahkan baris berikut ke .bazelrc
Anda:
common --registry="path/to/local/bcr/registry"
Direktori distribusi (dengan Bazel sebelum versi 7)
Untuk menyiapkan direktori distribusi, gunakan
--distdir
penanda. Anda perlu melakukan ini sekali
untuk setiap versi biner Bazel yang baru, karena
dependensi implisit bisa
berbeda untuk setiap rilis.
Untuk membangun dependensi ini di luar lingkungan airgapp Anda, pertama-tama periksa struktur pohon sumber Bazel dalam versi yang tepat:
git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"
cd "$BAZEL_DIR"
git checkout "$BAZEL_VERSION"
Kemudian, bangun tarball yang berisi dependensi waktu proses implisit untuk versi Bazel tertentu:
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 .bazelrc
entri:
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 merujuk pada satu set 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
perlu membangun //foo:bin
menggunakan toolchain yang mampu membuat 64-bit
file yang dapat dieksekusi, tetapi sistem build juga harus membangun berbagai alat yang digunakan selama
membangun dirinya sendiri—misalnya alat yang dibuat dari sumber, kemudian
digunakan dalam, misalnya, genrule, dan harus dibuat agar dapat berjalan 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 (//foo:bin
) dan satu atau beberapa alat exec, misalnya beberapa
pada library dasar. Library tersebut harus dibangun dua kali, sekali untuk eksekutif
dan sekali lagi untuk konfigurasi target. Bazel mengurus
memastikan bahwa kedua varian dibuat, dan bahwa file turunan disimpan
terpisah untuk menghindari gangguan; biasanya target seperti itu dapat
dibangun secara serentak,
karena mereka independen satu sama lain. Jika Anda melihat pesan progres
yang menunjukkan bahwa target tertentu dibuat dua kali, kemungkinan besar ini adalah
penjelasan.
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 mencaridefault_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 {i>file<i} 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 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 tujuan utama proyek Bazel adalah untuk memastikan peningkatan rebuild. 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 yang umum terjadi, sangat mudah untuk menghindari asumsi ini; menyinkronkan ke revisi file sebelumnya menyebabkan waktu modifikasi file tersebut berkurang; Sistem berbasis maket tidak akan dibuat ulang.
Secara lebih umum, saat 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}.
Manfaat bagi pengguna build inkremental yang benar adalah: lebih sedikit waktu yang terbuang karena
kebingungan. (Selain itu, waktu yang dihabiskan untuk menunggu build ulang yang disebabkan oleh penggunaan make
clean
, baik diperlukan maupun pencegahan, juga menjadi lebih sedikit.)
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 sampai Anda menjalankan berikutnya alat build 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 merusak: stabil
inkonsistensi. Jika build mencapai status tidak konsisten yang stabil, lalu diulang
pemanggilan alat build yang berhasil tidak memulihkan konsistensi: build
“terhenti”, dan {i>output-<i}nya tetap salah. Status stabil yang tidak konsisten
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 paling sederhana untuk mencapai build yang konsisten adalah dengan membuang semua output build sebelumnya dan mulai lagi: jadikan setiap build menjadi clean build. 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 di mana Anda tidak melakukan pengeditan, akan berada dalam keadaan yang konsisten. (Jika Anda mengedit file sumber selama bawaan, Bazel tidak memberikan jaminan tentang konsistensi hasil dari build saat ini. Namun, cara ini menjamin bahwa hasil dari build berikutnya akan memulihkan konsistensi.)
Seperti halnya jaminan, ada beberapa syaratnya: ada beberapa cara dalam keadaan tidak konsisten dengan Bazel. Kami tidak menjamin untuk menyelidiki masalah yang timbul dari upaya yang disengaja untuk menemukan {i>bug<i} dalam analisis dependensi inkremental, tetapi kami akan menyelidiki dan melakukan yang terbaik semua status tidak konsisten stabil yang timbul dari normal atau "masuk akal" penggunaan membangun aplikasi.
Jika Anda mendeteksi keadaan tidak konsisten yang stabil dengan Bazel, laporkan bug.
Eksekusi dengan sandbox
Bazel menggunakan {i>sandbox<i} 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
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 Google Kubernetes
Engine atau Debian,
namespace pengguna dinonaktifkan secara default karena keamanan
kekhawatiran Anda. 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, {i>sandbox<i} Bazel gagal
menjalankan aturan karena sistem
penyiapan. 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
pelacak masalah dan menyebutkan distribusi
Linux yang Anda gunakan sehingga kami dapat
selidiki dan berikan perbaikan dalam rilis berikutnya.
Fase build
Di Bazel, build terjadi dalam tiga fase berbeda; sebagai pengguna, memahami perbedaan di antara keduanya 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. Di beberapa build berikutnya, terutama jika tidak ada file BUILD yang berubah, terjadi pemuatan 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 diperlukan, 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. Di langkah ini, build menghabiskan sebagian besar waktu, mulai dari beberapa detik hingga lebih dari satu jam untuk buat. 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.