Catat Tanggalnya: BazelCon 2023 akan diadakan pada 24-25 Oktober di Google Munich! Pelajari lebih lanjut

Tutorial Bazel: Membuat Project C++

Laporkan masalah Lihat sumber

Pengantar

Baru menggunakan Bazel? Anda berada di tempat yang tepat. Ikuti tutorial First Build ini untuk pengantar sederhana dalam menggunakan Bazel. Tutorial ini mendefinisikan istilah kunci saat digunakan dalam konteks Bazel dan memandu Anda melalui dasar-dasar alur kerja Bazel. Mulai dengan alat yang diperlukan, Anda akan mem-build dan menjalankan tiga project dengan kompleksitas yang lebih tinggi serta mempelajari bagaimana dan mengapa project tersebut menjadi lebih kompleks.

Meskipun Bazel adalah sistem build yang mendukung build multibahasa, tutorial ini menggunakan project C++ sebagai contoh dan memberikan panduan umum dan alur yang berlaku untuk sebagian besar bahasa.

Perkiraan waktu penyelesaian: 30 menit.

Prasyarat

Mulailah dengan menginstal Bazel, jika Anda belum menginstalnya. Tutorial ini menggunakan Git untuk kontrol sumber, jadi untuk hasil terbaik, instal Git juga.

Selanjutnya, ambil project contoh dari repositori GitHub Bazel dengan menjalankan hal berikut di alat command line pilihan Anda:

git clone https://github.com/bazelbuild/examples

Project contoh untuk tutorial ini berada di direktori examples/cpp-tutorial.

Lihat strukturnya di bawah ini:

examples
└── cpp-tutorial
    ├──stage1
    │  ├── main
    │  │   ├── BUILD
    │  │   └── hello-world.cc
    │  └── WORKSPACE
    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE
    └──stage3
       ├── main
       │   ├── BUILD
       │   ├── hello-world.cc
       │   ├── hello-greet.cc
       │   └── hello-greet.h
       ├── lib
       │   ├── BUILD
       │   ├── hello-time.cc
       │   └── hello-time.h
       └── WORKSPACE

Ada tiga kumpulan file, setiap set mewakili satu tahap dalam tutorial ini. Pada tahap pertama, Anda akan mem-build satu target yang berada dalam satu paket. Pada tahap kedua, Anda akan membuat biner dan library dari satu paket. Pada tahap ketiga dan terakhir, Anda akan mem-build project dengan beberapa paket dan mem-build-nya dengan beberapa target.

Ringkasan: Pengantar

Dengan menginstal Bazel (dan Git) dan meng-clone repositori untuk tutorial ini, Anda telah menyiapkan fondasi untuk build pertama Anda dengan Bazel. Lanjutkan ke bagian berikutnya untuk menentukan beberapa persyaratan dan menyiapkan ruang kerja.

Memulai

Siapkan ruang kerja

Sebelum dapat membuat project, Anda perlu menyiapkan ruang kerjanya. Ruang kerja adalah direktori yang menyimpan file sumber project dan output build Bazel. File ini juga berisi file penting berikut:

  • WORKSPACE file , yang mengidentifikasi direktori dan isinya sebagai ruang kerja Bazel dan berada di root struktur direktori project.
  • Satu atau beberapa BUILD files , yang memberi tahu Bazel cara mem-build berbagai bagian project. Direktori dalam ruang kerja yang berisi file BUILD adalah paket. (Selengkapnya tentang paket nanti dalam tutorial ini.)

Dalam project mendatang, untuk menetapkan direktori sebagai ruang kerja Bazel, buat file kosong bernama WORKSPACE di direktori tersebut. Untuk keperluan tutorial ini, file WORKSPACE sudah ada di setiap tahap.

CATATAN: Saat Bazel membuat project, semua input harus berada di ruang kerja yang sama. File yang berada di ruang kerja yang berbeda tidak saling bergantung, kecuali jika ditautkan. Informasi lebih mendetail tentang aturan ruang kerja dapat ditemukan di panduan ini.

Memahami file BUILD

File BUILD berisi beberapa jenis petunjuk untuk Bazel. Setiap file BUILD memerlukan setidaknya satu aturan sebagai kumpulan petunjuk, yang memberi tahu Bazel cara mem-build output yang diinginkan, seperti biner atau library yang dapat dieksekusi. Setiap instance aturan build di file BUILD disebut target dan mengarah ke kumpulan file sumber dan dependensi tertentu. Target juga dapat mengarah ke target lain.

Lihat file BUILD di direktori cpp-tutorial/stage1/main:

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
)

Dalam contoh kami, target hello-world membuat instance cc_binary rule bazel bawaan. Aturan ini memberi tahu Bazel untuk membuat biner mandiri yang dapat dieksekusi dari file sumber hello-world.cc tanpa dependensi.

Ringkasan: memulai

Sekarang Anda telah memahami beberapa istilah utama, dan artinya dalam konteks project ini dan Bazel secara umum. Di bagian berikutnya, Anda akan mem-build dan menguji Tahap 1 project.

Tahap 1: target tunggal, paket tunggal

Sekarang saatnya membuat bagian pertama project. Untuk referensi visual, struktur bagian Tahap 1 project ini adalah:

examples
└── cpp-tutorial
    └──stage1
       ├── main
       │   ├── BUILD
       │   └── hello-world.cc
       └── WORKSPACE

Jalankan perintah berikut untuk berpindah ke direktori cpp-tutorial/stage1:

cd cpp-tutorial/stage1

Selanjutnya, jalankan:

bazel build //main:hello-world

Dalam label target, bagian //main: adalah lokasi file BUILD yang terkait dengan root ruang kerja, dan hello-world adalah nama target dalam file BUILD.

Bazel menghasilkan sesuatu yang terlihat seperti ini:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 2.267s, Critical Path: 0.25s

Anda baru saja membuat target Bazel pertama. Bazel menempatkan output build pada direktori bazel-bin di root ruang kerja.

Sekarang uji biner Anda yang baru dibuat, yaitu:

bazel-bin/main/hello-world

Ini akan menghasilkan pesan “Hello world” yang dicetak.

Berikut adalah grafik dependensi Tahap 1:

Grafik dependensi untuk hello-world menampilkan satu target dengan satu file sumber.

Ringkasan: tahap 1

Setelah menyelesaikan build pertama, Anda kini memiliki gambaran dasar tentang struktur build. Pada tahap berikutnya, Anda akan menambahkan kompleksitas dengan menambahkan target lain.

Tahap 2: beberapa target build

Meskipun satu target sudah cukup untuk project kecil, Anda mungkin ingin membagi project yang lebih besar menjadi beberapa target dan paket. Hal ini memungkinkan build inkremental cepat, yaitu Bazel hanya mem-build ulang apa yang berubah, dan mempercepat build Anda dengan mem-build beberapa bagian project sekaligus. Tahapan tutorial ini menambahkan target, dan yang berikutnya menambahkan paket.

Ini adalah direktori yang Anda gunakan untuk Tahap 2:

    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE

Lihat file BUILD di direktori cpp-tutorial/stage2/main berikut:

cc_library(
    name = "hello-greet",
    srcs = ["hello-greet.cc"],
    hdrs = ["hello-greet.h"],
)

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
    ],
)

Dengan file BUILD ini, Bazel akan terlebih dahulu mem-build library hello-greet (menggunakan cc_library rule bawaan Bazel), lalu biner hello-world. Atribut deps dalam target hello-world memberi tahu Bazel bahwa library hello-greet diperlukan untuk membuat biner hello-world.

Sebelum dapat mem-build project versi baru ini, Anda perlu mengubah direktori, beralih ke direktori cpp-tutorial/stage2 dengan menjalankan:

cd ../stage2

Sekarang, Anda dapat mem-build biner baru menggunakan perintah berikut yang dikenal:

bazel build //main:hello-world

Sekali lagi, Bazel menghasilkan sesuatu yang terlihat seperti ini:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 2.399s, Critical Path: 0.30s

Sekarang Anda dapat menguji biner yang baru dibuat, yang menampilkan “Hello world” lainnya:

bazel-bin/main/hello-world

Jika sekarang Anda telah memodifikasi hello-greet.cc dan mem-build ulang project, Bazel hanya akan mengompilasi ulang file tersebut.

Dengan melihat grafik dependensi, Anda dapat melihat bahwa hello-world bergantung pada input tambahan bernama hello-greet:

Grafik dependensi untuk `hello-world` menampilkan perubahan dependensi setelah file diubah.

Ringkasan: tahap 2

Sekarang Anda telah membuat project dengan dua target. Target hello-world akan mem-build satu file sumber dan bergantung pada satu target lainnya (//main:hello-greet), yang mem-build dua file sumber tambahan. Di bagian berikutnya, ambil langkah berikutnya dan tambahkan paket lain.

Tahap 3: beberapa paket

Tahap berikutnya ini menambahkan lapisan detail lain dan mem-build project dengan beberapa paket. Lihat struktur dan isi direktori cpp-tutorial/stage3 di bawah ini:

└──stage3
   ├── main
   │   ├── BUILD
   │   ├── hello-world.cc
   │   ├── hello-greet.cc
   │   └── hello-greet.h
   ├── lib
   │   ├── BUILD
   │   ├── hello-time.cc
   │   └── hello-time.h
   └── WORKSPACE

Anda dapat melihat bahwa sekarang ada dua subdirektori, dan masing-masing berisi file BUILD. Oleh karena itu, kepada Bazel, ruang kerja kini berisi dua paket: lib dan main.

Lihat file lib/BUILD:

cc_library(
    name = "hello-time",
    srcs = ["hello-time.cc"],
    hdrs = ["hello-time.h"],
    visibility = ["//main:__pkg__"],
)

Dan di file main/BUILD:

cc_library(
    name = "hello-greet",
    srcs = ["hello-greet.cc"],
    hdrs = ["hello-greet.h"],
)

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
    deps = [
        ":hello-greet",
        "//lib:hello-time",
    ],
)

Target hello-world dalam paket utama bergantung pada target hello-time dalam paket lib (sehingga label target //lib:hello-time) - Bazel mengetahui hal ini melalui atribut deps. Anda dapat melihatnya di grafik dependensi:

Grafik dependensi untuk `hello-world` menampilkan cara target dalam paket utama bergantung pada target dalam paket `lib`.

Agar build berhasil, buat target //lib:hello-time di lib/BUILD secara eksplisit terlihat oleh target di main/BUILD menggunakan atribut visibilitas. Hal ini karena secara default target hanya terlihat oleh target lain dalam file BUILD yang sama. Bazel menggunakan visibilitas target untuk mencegah masalah seperti library yang berisi detail implementasi yang bocor ke dalam API publik.

Sekarang, buat versi final project ini. Beralih ke direktori cpp-tutorial/stage3 dengan menjalankan:

cd  ../stage3

Sekali lagi, jalankan perintah berikut:

bazel build //main:hello-world

Bazel menghasilkan sesuatu yang terlihat seperti ini:

INFO: Found 1 target...
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 0.167s, Critical Path: 0.00s

Sekarang uji biner terakhir tutorial ini untuk pesan Hello world akhir:

bazel-bin/main/hello-world

Ringkasan: tahap 3

Sekarang Anda telah mem-build project sebagai dua paket dengan tiga target dan memahami dependensi di antara keduanya, yang melengkapi Anda untuk maju dan mem-build project mendatang dengan Bazel. Di bagian berikutnya, lihat cara melanjutkan perjalanan Bazel.

Langkah berikutnya

Kini Anda telah menyelesaikan build dasar pertama dengan Bazel, tetapi ini baru memulai. Berikut adalah beberapa referensi untuk terus belajar dengan Bazel:

Selamat membangun!