Tutorial ini membahas dasar-dasar membangun aplikasi Java dengan
Bazel. Anda akan menyiapkan ruang kerja Anda dan membangun project Java sederhana yang
mengilustrasikan konsep utama Bazel, seperti target dan file BUILD
.
Perkiraan waktu penyelesaian: 30 menit.
Yang akan Anda pelajari
Dalam tutorial ini, Anda akan mempelajari cara:
- Membuat target
- Memvisualisasikan dependensi project
- Bagi project menjadi beberapa target dan paket
- Mengontrol visibilitas target di berbagai paket
- Mereferensikan target melalui label
- Men-deploy target
Sebelum memulai
Instal Bazel
Untuk mempersiapkan tutorial, Instal Bazel terlebih dahulu jika Anda belum menginstalnya.
Menginstal JDK
Instal Java JDK (versi yang lebih disukai adalah 11, namun versi antara 8 dan 15 didukung).
Setel variabel lingkungan JAVA_HOME agar mengarah ke JDK.
Di Linux/macOS:
export JAVA_HOME="$(dirname $(dirname $(realpath $(which javac))))"
Di Windows:
- Buka Control Panel.
- Buka "Sistem dan Keamanan" > "Sistem" > "Setelan Sistem Lanjutan" > "Lanjutan" tab > "Variabel Lingkungan..." .
- Di bagian "Variabel pengguna" (yang ada di atas), klik "Baru...".
- Di bagian "Nama variabel" , masukkan
JAVA_HOME
. - Klik "Jelajahi Direktori...".
- Buka direktori JDK (misalnya
C:\Program Files\Java\jdk1.8.0_152
). - Klik "OK" di semua jendela dialog.
Mendapatkan contoh project
Ambil project contoh dari repositori GitHub Bazel:
git clone https://github.com/bazelbuild/examples
Project contoh untuk tutorial ini ada dalam examples/java-tutorial
dan disusun sebagai berikut:
java-tutorial
├── BUILD
├── src
│ └── main
│ └── java
│ └── com
│ └── example
│ ├── cmdline
│ │ ├── BUILD
│ │ └── Runner.java
│ ├── Greeting.java
│ └── ProjectRunner.java
└── WORKSPACE
Membangun dengan Bazel
Menyiapkan ruang kerja
Sebelum dapat membuat project, Anda perlu menyiapkan ruang kerjanya. Ruang kerja adalah direktori yang menyimpan file sumber proyek Anda dan {i>output<i} build Bazel. Ini juga berisi file yang dikenali Bazel sebagai khusus:
File
WORKSPACE
, yang mengidentifikasi direktori dan kontennya sebagai {i>workspace <i}dan berada di akar dari struktur direktori proyek,Satu atau beberapa file
BUILD
, yang memberi tahu Bazel cara membuat bagian yang berbeda dari menyelesaikan proyek tersebut. (Direktori dalam ruang kerja yang berisi fileBUILD
adalah paket. Anda akan belajar tentang paket nanti dalam tutorial ini.)
Untuk menetapkan direktori sebagai ruang kerja Bazel, buat file kosong bernama
WORKSPACE
di direktori tersebut.
Saat Bazel membuat project, semua input dan dependensi harus sama Workspace. File yang berada di ruang kerja lain terpisah dari satu ruang kerja satu lagi kecuali ditautkan, yang berada di luar cakupan tutorial ini.
Memahami file BUILD
File BUILD
berisi beberapa jenis petunjuk yang berbeda untuk Bazel.
Jenis yang paling penting adalah aturan build, yang memberi tahu Bazel cara membuat
{i>output<i} yang diinginkan, seperti {i>executable<i}
atau {i>library<i}. Setiap instance
aturan build di file BUILD
disebut target dan mengarah ke
set tertentu dari file sumber
dan dependensi. Target juga dapat menunjuk ke
target.
Lihat file java-tutorial/BUILD
:
java_binary(
name = "ProjectRunner",
srcs = glob(["src/main/java/com/example/*.java"]),
)
Dalam contoh kita, target ProjectRunner
membuat instance bawaan Bazel
Aturan java_binary
. Aturan itu memberitahu
Bazel untuk
membuat file .jar
dan skrip shell wrapper (keduanya dinamai sesuai target).
Atribut pada target secara eksplisit menyatakan dependensi dan opsinya.
Meskipun atribut name
bersifat wajib, banyak yang opsional. Misalnya, di kolom
ProjectRunner
target aturan, name
adalah nama target, srcs
menentukan
file sumber yang digunakan Bazel untuk membangun target, dan main_class
menentukan
class yang berisi metode utama. (Anda mungkin telah memperhatikan bahwa contoh
menggunakan glob untuk meneruskan kumpulan file sumber ke Bazel
alih-alih mencantumkannya satu per satu.)
Membangun project
Untuk membuat project contoh, buka direktori java-tutorial
dan jalankan:
bazel build //:ProjectRunner
Di label target, bagian //
adalah lokasi file BUILD
relatif terhadap {i>root <i}ruang kerja (dalam hal ini, {i>root<i} itu sendiri),
dan ProjectRunner
adalah nama target dalam file BUILD
. (Anda akan
pelajari label target secara lebih mendetail di akhir tutorial ini.)
Bazel menghasilkan output yang mirip dengan berikut ini:
INFO: Found 1 target...
Target //:ProjectRunner up-to-date:
bazel-bin/ProjectRunner.jar
bazel-bin/ProjectRunner
INFO: Elapsed time: 1.021s, Critical Path: 0.83s
Selamat, kamu baru saja membangun target Bazel pertamamu! Tempat bazel build
menghasilkan output di direktori bazel-bin
di root ruang kerja. Jelajahi
untuk mendapatkan ide
tentang struktur {i>output<i} Bazel.
Sekarang uji biner yang baru Anda bangun:
bazel-bin/ProjectRunner
Meninjau grafik dependensi
Bazel memerlukan dependensi build yang dideklarasikan secara eksplisit dalam file BUILD. Bazel menggunakan pernyataan tersebut untuk membuat grafik dependensi proyek, yang memungkinkan build inkremental yang akurat.
Untuk memvisualisasikan dependensi project contoh, Anda bisa membuat teks grafik dependensi dengan menjalankan perintah ini di root workspace:
bazel query --notool_deps --noimplicit_deps "deps(//:ProjectRunner)" --output graph
Perintah di atas memberi tahu Bazel untuk mencari semua dependensi untuk target
//:ProjectRunner
(tidak termasuk dependensi implisit dan host), lalu memformat
output sebagai grafik.
Kemudian, tempel teks ke GraphViz.
Seperti yang dapat Anda lihat, proyek ini memiliki satu target yang membangun dua file sumber dengan tidak ada dependensi tambahan:
Setelah menyiapkan ruang kerja Anda, bangun project Anda, dan periksa dependensi, maka Anda dapat menambahkan beberapa kerumitan.
Sempurnakan build Bazel Anda
Meskipun satu target sudah cukup untuk project kecil, sebaiknya Anda membagi dari proyek yang lebih besar menjadi beberapa target dan paket untuk mempercepat proses build (yaitu, hanya membangun ulang apa yang berubah) dan untuk mempercepat build Anda dengan membangun beberapa bagian proyek sekaligus.
Menentukan beberapa target build
Anda dapat membagi build contoh project menjadi dua target. Ganti konten
file java-tutorial/BUILD
dengan kode berikut:
java_binary(
name = "ProjectRunner",
srcs = ["src/main/java/com/example/ProjectRunner.java"],
main_class = "com.example.ProjectRunner",
deps = [":greeter"],
)
java_library(
name = "greeter",
srcs = ["src/main/java/com/example/Greeting.java"],
)
Dengan konfigurasi ini, Bazel akan terlebih dahulu membangun library greeter
, lalu
Biner ProjectRunner
. Atribut deps
dalam java_binary
memberi tahu Bazel bahwa
library greeter
diperlukan untuk membangun biner ProjectRunner
.
Untuk membuat versi baru project ini, jalankan perintah berikut:
bazel build //:ProjectRunner
Bazel menghasilkan output yang mirip dengan berikut ini:
INFO: Found 1 target...
Target //:ProjectRunner up-to-date:
bazel-bin/ProjectRunner.jar
bazel-bin/ProjectRunner
INFO: Elapsed time: 2.454s, Critical Path: 1.58s
Sekarang uji biner yang baru Anda bangun:
bazel-bin/ProjectRunner
Jika sekarang Anda mengubah ProjectRunner.java
dan mem-build ulang project, hanya Bazel
akan mengompilasi ulang file tersebut.
Dengan melihat grafik dependensi, Anda dapat melihat bahwa ProjectRunner
bergantung pada
input yang sama seperti sebelumnya, tetapi struktur build-nya berbeda:
Sekarang Anda telah membangun proyek dengan dua target. Target ProjectRunner
di-build
dua file sumber dan bergantung pada satu target lain (:greeter
), yang membuat
satu file sumber tambahan.
Menggunakan beberapa paket
Sekarang, mari kita bagi project menjadi beberapa paket. Jika Anda melihat
src/main/java/com/example/cmdline
, Anda dapat melihat bahwa file tersebut juga berisi
file BUILD
, plus beberapa file sumber. Oleh karena itu, bagi Bazel, ruang kerja sekarang
berisi dua paket, //src/main/java/com/example/cmdline
dan //
(sejak
ada file BUILD
di root ruang kerja).
Lihat file src/main/java/com/example/cmdline/BUILD
:
java_binary(
name = "runner",
srcs = ["Runner.java"],
main_class = "com.example.cmdline.Runner",
deps = ["//:greeter"],
)
Target runner
bergantung pada target greeter
dalam paket //
(oleh karena itu
label target //:greeter
) - Bazel mengetahui hal ini melalui atribut deps
.
Lihatlah grafik dependensi:
Namun, agar build berhasil, Anda harus secara eksplisit memberikan target runner
dalam visibilitas //src/main/java/com/example/cmdline/BUILD
terhadap target dalam
//BUILD
menggunakan atribut visibility
. Hal ini karena secara default target
hanya terlihat oleh target lain dalam file BUILD
yang sama. (Bazel menggunakan target
visibilitas untuk mencegah masalah seperti library yang berisi detail implementasi
yang bocor ke API publik.)
Untuk melakukannya, tambahkan atribut visibility
ke target greeter
di
java-tutorial/BUILD
seperti yang ditunjukkan di bawah ini:
java_library(
name = "greeter",
srcs = ["src/main/java/com/example/Greeting.java"],
visibility = ["//src/main/java/com/example/cmdline:__pkg__"],
)
Sekarang Anda dapat membuat paket baru dengan menjalankan perintah berikut di root ruang kerja:
bazel build //src/main/java/com/example/cmdline:runner
Bazel menghasilkan output yang mirip dengan berikut ini:
INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner up-to-date:
bazel-bin/src/main/java/com/example/cmdline/runner.jar
bazel-bin/src/main/java/com/example/cmdline/runner
INFO: Elapsed time: 1.576s, Critical Path: 0.81s
Sekarang uji biner yang baru Anda bangun:
./bazel-bin/src/main/java/com/example/cmdline/runner
Sekarang Anda telah mengubah project untuk di-build sebagai dua paket, masing-masing berisi satu paket menargetkan, dan memahami dependensi di antara mereka.
Menggunakan label untuk mereferensikan target
Dalam file BUILD
dan command line, Bazel menggunakan label target untuk mereferensikan
target - misalnya, //:ProjectRunner
atau
//src/main/java/com/example/cmdline:runner
. Sintaksnya adalah sebagai berikut:
//path/to/package:target-name
Jika targetnya adalah target aturan, path/to/package
adalah jalur ke
yang berisi file BUILD
, dan target-name
adalah nama yang Anda berikan
targetnya di file BUILD
(atribut name
). Jika targetnya adalah file
target, maka path/to/package
adalah jalur ke root paket, dan
target-name
adalah nama file target, termasuk jalur lengkapnya.
Saat mereferensikan target di root repositori, jalur paket kosong,
cukup gunakan //:target-name
. Saat mereferensikan target dalam BUILD
yang sama
, Anda bahkan dapat melewati ID root ruang kerja //
dan cukup menggunakan
:target-name
.
Misalnya, untuk target di file java-tutorial/BUILD
, Anda tidak perlu melakukannya
menentukan jalur paket, karena root ruang kerja itu sendiri adalah paket (//
), dan
dua label target Anda hanya //:ProjectRunner
dan //:greeter
.
Namun, untuk target dalam file //src/main/java/com/example/cmdline/BUILD
, Anda
harus menentukan jalur paket lengkap //src/main/java/com/example/cmdline
dan label target Anda adalah //src/main/java/com/example/cmdline:runner
.
Kemas target Java untuk deployment
Sekarang, mari kita kemas target Java untuk deployment dengan membangun biner dengan semua dependensi runtime-nya. Hal ini memungkinkan Anda menjalankan biner di luar lingkungan pengembangan Anda.
Seperti yang Anda ingat, aturan build java_binary
menghasilkan .jar
dan skrip shell wrapper. Lihat isi dari
runner.jar
menggunakan perintah ini:
jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar
Isinya adalah:
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
Seperti yang dapat Anda lihat, runner.jar
berisi Runner.class
, tetapi bukan dependensinya,
Greeting.class
. Skrip runner
yang dihasilkan Bazel menambahkan greeter.jar
ke classpath, jadi jika dibiarkan seperti ini, ia akan berjalan secara lokal, tetapi
tidak akan berjalan secara
mandiri di komputer lain. Untungnya, aturan java_binary
memungkinkan Anda untuk membangun biner mandiri yang dapat di-deploy. Untuk membuatnya, tambahkan
_deploy.jar
ke nama target:
bazel build //src/main/java/com/example/cmdline:runner_deploy.jar
Bazel menghasilkan output yang mirip dengan berikut ini:
INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner_deploy.jar up-to-date:
bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
INFO: Elapsed time: 1.700s, Critical Path: 0.23s
Anda baru saja membuat runner_deploy.jar
, yang dapat dijalankan secara mandiri
lingkungan pengembangan Anda karena berisi runtime yang diperlukan
dependensi. Lihat konten JAR mandiri ini menggunakan
perintah yang sama seperti sebelumnya:
jar tf bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
Kontennya mencakup semua class yang diperlukan untuk dijalankan:
META-INF/
META-INF/MANIFEST.MF
build-data.properties
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
com/example/Greeting.class
Bacaan lebih lanjut
Untuk mengetahui detail selengkapnya, lihat:
rules_jvm_external untuk aturan untuk mengelola dependensi Maven transitif.
Dependensi Eksternal untuk mempelajari lebih lanjut cara bekerja dengan repositori lokal dan jarak jauh.
Aturan lainnya untuk mempelajari Bazel lebih lanjut.
Tutorial build C++ untuk memulai pembuatan Project C++ dengan Bazel.
Tutorial aplikasi Android dan Tutorial aplikasi iOS untuk mulai menggunakan membangun aplikasi seluler untuk Android dan iOS dengan Bazel.
Selamat membangun!