Giới thiệu
Bạn mới sử dụng Bazel? Bạn đã đến đúng nơi. Hãy làm theo hướng dẫn Tạo bản dựng đầu tiên này để được giới thiệu đơn giản về cách sử dụng Bazel. Hướng dẫn này định nghĩa các thuật ngữ chính khi chúng được sử dụng trong bối cảnh của Bazel và hướng dẫn bạn các kiến thức cơ bản về quy trình làm việc của Bazel. Bắt đầu với các công cụ cần thiết, bạn sẽ tạo và chạy 3 dự án có độ phức tạp tăng dần, đồng thời tìm hiểu cách và lý do các dự án này trở nên phức tạp hơn.
Mặc dù Bazel là một hệ thống xây dựng hỗ trợ các bản dựng đa ngôn ngữ, nhưng hướng dẫn này sử dụng một dự án C++ làm ví dụ và cung cấp các nguyên tắc và quy trình chung áp dụng cho hầu hết các ngôn ngữ.
Thời gian hoàn thành dự kiến: 30 phút.
Điều kiện tiên quyết
Bắt đầu bằng cách cài đặt Bazel, nếu bạn chưa cài đặt. Hướng dẫn này sử dụng Git để kiểm soát nguồn, vì vậy, để có kết quả tốt nhất, hãy cài đặt Git nữa.
Tiếp theo, hãy truy xuất dự án mẫu từ kho lưu trữ GitHub của Bazel bằng cách chạy lệnh sau trong công cụ dòng lệnh mà bạn chọn:
git clone https://github.com/bazelbuild/examplesDự án mẫu cho hướng dẫn này nằm trong examples/cpp-tutorial
thư mục.
Hãy xem cấu trúc của dự án này:
examples
└── cpp-tutorial
├──stage1
│ ├── main
│ │ ├── BUILD
│ │ └── hello-world.cc
│ └── MODULE.bazel
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── MODULE.bazel
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── MODULE.bazel
Có 3 nhóm tệp, mỗi nhóm đại diện cho một giai đoạn trong hướng dẫn này. Trong giai đoạn đầu tiên, bạn sẽ tạo một mục tiêu duy nhất nằm trong một gói duy nhất. Trong giai đoạn thứ hai, bạn sẽ tạo cả tệp nhị phân và thư viện từ một gói duy nhất. Trong giai đoạn thứ ba và cuối cùng, bạn sẽ tạo một dự án có nhiều gói và tạo dự án đó bằng nhiều mục tiêu.
Tóm tắt: Giới thiệu
Bằng cách cài đặt Bazel (và Git) cũng như sao chép kho lưu trữ cho hướng dẫn này, bạn đã đặt nền tảng cho bản dựng đầu tiên bằng Bazel. Hãy tiếp tục chuyển sang phần tiếp theo để xác định một số thuật ngữ và thiết lập không gian làm việc.
Bắt đầu
Trước khi có thể tạo một dự án, bạn cần thiết lập không gian làm việc cho dự án đó. Không gian làm việc là một thư mục chứa các tệp nguồn của dự án và đầu ra bản dựng của Bazel. Không gian làm việc cũng chứa các tệp quan trọng sau:
- Tệp
MODULE.bazelxác định thư mục và nội dung của thư mục đó là không gian làm việc của Bazel và nằm ở gốc của cấu trúc thư mục của dự án. Đây cũng là nơi bạn chỉ định các phần phụ thuộc bên ngoài. - Một hoặc nhiều
BUILDtệp cho Bazel biết cách tạo các phần khác nhau của dự án. Một thư mục trong không gian làm việc chứa tệpBUILDlà một gói. (Thông tin thêm về các gói trong hướng dẫn này.)
Trong các dự án trong tương lai, để chỉ định một thư mục là không gian làm việc của Bazel, hãy tạo một
tệp trống có tên là MODULE.bazel trong thư mục đó. Đối với mục đích của hướng dẫn này, tệp MODULE.bazel đã có trong mỗi giai đoạn.
Tìm hiểu tệp BUILD
Tệp BUILD chứa nhiều loại hướng dẫn cho Bazel. Mỗi
BUILD tệp yêu cầu ít nhất một
quy tắc dưới dạng một tập hợp hướng dẫn,
cho Bazel biết cách tạo đầu ra mà bạn muốn, chẳng hạn như tệp nhị phân thực thi
hoặc thư viện. Mỗi thực thể của một quy tắc bản dựng trong tệp BUILD được gọi là một
mục tiêu và trỏ đến một
tập hợp cụ thể gồm các tệp nguồn và
phần phụ thuộc. Một mục tiêu cũng có thể
trỏ đến các mục tiêu khác.
Hãy xem tệp BUILD trong thư mục cpp-tutorial/stage1/main:
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
Trong ví dụ của chúng tôi, mục tiêu hello-world khởi tạo quy tắc
cc_binary tích hợp của Bazel. Quy tắc này
cho Bazel biết cách tạo một tệp nhị phân thực thi độc lập từ tệp nguồn
hello-world.cc> mà không có phần phụ thuộc.
Tóm tắt: bắt đầu
Bây giờ, bạn đã quen thuộc với một số thuật ngữ chính và ý nghĩa của chúng trong bối cảnh của dự án này và Bazel nói chung. Trong phần tiếp theo, bạn sẽ tạo và kiểm thử Giai đoạn 1 của dự án.
Giai đoạn 1: một mục tiêu, một gói
Đã đến lúc tạo phần đầu tiên của dự án. Để tham khảo trực quan, cấu trúc của phần Giai đoạn 1 của dự án là:
examples
└── cpp-tutorial
└──stage1
├── main
│ ├── BUILD
│ └── hello-world.cc
└── MODULE.bazel
Chạy lệnh sau để chuyển đến thư mục cpp-tutorial/stage1:
cd cpp-tutorial/stage1Tiếp theo, hãy chạy:
bazel build //main:hello-worldTrong nhãn mục tiêu, phần //main: là vị trí của tệp BUILD
so với gốc của không gian làm việc và hello-world là tên mục tiêu trong
tệp BUILD.
Bazel tạo ra một nội dung như sau:
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
Bạn vừa tạo mục tiêu Bazel đầu tiên. Bazel đặt đầu ra bản dựng trong thư mục
bazel-bin ở gốc của không gian làm việc.
Bây giờ, hãy kiểm thử tệp nhị phân mới tạo của bạn:
bazel-bin/main/hello-worldKết quả là một thông báo "Hello world" được in.
Sau đây là biểu đồ phần phụ thuộc của Giai đoạn 1:

Tóm tắt: giai đoạn 1
Sau khi hoàn tất bản dựng đầu tiên, bạn sẽ có ý tưởng cơ bản về cấu trúc của một bản dựng. Trong giai đoạn tiếp theo, bạn sẽ tăng độ phức tạp bằng cách thêm một mục tiêu khác.
Giai đoạn 2: nhiều mục tiêu bản dựng
Mặc dù một mục tiêu là đủ cho các dự án nhỏ, nhưng bạn có thể muốn chia các dự án lớn hơn thành nhiều mục tiêu và gói. Điều này cho phép tạo bản dựng gia tăng nhanh chóng – tức là Bazel chỉ tạo lại những gì đã thay đổi – và tăng tốc bản dựng bằng cách tạo nhiều phần của một dự án cùng một lúc. Giai đoạn này của hướng dẫn sẽ thêm một mục tiêu và giai đoạn tiếp theo sẽ thêm một gói.
Đây là thư mục bạn đang làm việc cho Giai đoạn 2:
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── MODULE.bazel
Hãy xem tệp BUILD trong thư mục cpp-tutorial/stage2/main:
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",
],
)
Với tệp BUILD này, Bazel sẽ tạo thư viện hello-greet (sử dụng
quy tắc cc_library
tích hợp của Bazel), sau đó là tệp nhị phân
hello-world. Thuộc tính deps trong mục tiêu hello-world cho
Bazel biết rằng thư viện hello-greet là bắt buộc để tạo tệp hello-world
nhị phân.
Trước khi có thể tạo phiên bản mới này của dự án, bạn cần thay đổi
thư mục, chuyển sang thư mục cpp-tutorial/stage2 bằng cách chạy:
cd ../stage2Bây giờ, bạn có thể tạo tệp nhị phân mới bằng lệnh quen thuộc sau:
bazel build //main:hello-worldMột lần nữa, Bazel tạo ra một nội dung như sau:
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
Bây giờ, bạn có thể kiểm thử tệp nhị phân mới tạo của mình, tệp này sẽ trả về một "Hello
world" khác:
bazel-bin/main/hello-worldNếu bạn sửa đổi hello-greet.cc và tạo lại dự án, Bazel sẽ chỉ
biên dịch lại tệp đó.
Nhìn vào biểu đồ phần phụ thuộc, bạn có thể thấy rằng hello-world phụ thuộc vào một
dữ liệu đầu vào bổ sung có tên là hello-greet:

Tóm tắt: giai đoạn 2
Bây giờ, bạn đã tạo dự án với 2 mục tiêu. Mục tiêu hello-world tạo
một tệp nguồn và phụ thuộc vào một mục tiêu khác (//main:hello-greet), mục tiêu này
tạo 2 tệp nguồn bổ sung. Trong phần tiếp theo, hãy tiến thêm một bước nữa
và thêm một gói khác.
Giai đoạn 3: nhiều gói
Giai đoạn tiếp theo này sẽ thêm một lớp phức tạp khác và tạo một dự án có
nhiều gói. Hãy xem cấu trúc và nội dung của thư mục
cpp-tutorial/stage3
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── MODULE.bazel
Bạn có thể thấy rằng hiện có 2 thư mục con và mỗi thư mục chứa một BUILD
tệp. Do đó, đối với Bazel, không gian làm việc hiện chứa 2 gói: lib và
main.
Hãy xem tệp lib/BUILD:
cc_library(
name = "hello-time",
srcs = ["hello-time.cc"],
hdrs = ["hello-time.h"],
visibility = ["//main:__pkg__"],
)
Và tệp 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",
],
)
Mục tiêu hello-world trong gói chính phụ thuộc vào mục tiêu hello-time
trong gói lib (do đó, nhãn mục tiêu //lib:hello-time) – Bazel biết
điều này thông qua thuộc tính deps. Bạn có thể thấy điều này được phản ánh trong biểu đồ phần phụ thuộc
graph:

Để bản dựng thành công, bạn hãy hiển thị rõ ràng mục tiêu //lib:hello-time trong lib/BUILD
cho các mục tiêu trong main/BUILD bằng thuộc tính hiển thị.
Điều này là do theo mặc định, các mục tiêu chỉ hiển thị cho các mục tiêu khác trong cùng một
BUILD tệp. Bazel sử dụng khả năng hiển thị mục tiêu để ngăn chặn các vấn đề như thư viện
chứa thông tin chi tiết về việc triển khai bị rò rỉ vào các API công khai.
Bây giờ, hãy tạo phiên bản cuối cùng này của dự án. Chuyển sang cpp-tutorial/stage3
thư mục bằng cách chạy:
cd ../stage3Một lần nữa, hãy chạy lệnh sau:
bazel build //main:hello-worldBazel tạo ra một nội dung như sau:
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
Bây giờ, hãy kiểm thử tệp nhị phân cuối cùng của hướng dẫn này để có thông báo Hello world cuối cùng:
bazel-bin/main/hello-worldTóm tắt: giai đoạn 3
Bây giờ, bạn đã tạo dự án dưới dạng 2 gói có 3 mục tiêu và hiểu các phần phụ thuộc giữa chúng, điều này giúp bạn có thể tiếp tục và tạo các dự án trong tương lai bằng Bazel. Trong phần tiếp theo, hãy xem cách tiếp tục hành trình Bazel của bạn.
Các bước tiếp theo
Bây giờ, bạn đã hoàn tất bản dựng cơ bản đầu tiên bằng Bazel, nhưng đây chỉ là bước khởi đầu. Sau đây là một số tài nguyên khác để tiếp tục tìm hiểu về Bazel:
- Để tiếp tục tập trung vào C++, hãy đọc về các trường hợp sử dụng bản dựng C++ phổ biến.
- Để bắt đầu tạo các ứng dụng khác bằng Bazel, hãy xem các hướng dẫn về Java, ứng dụng Android hoặc ứng dụng iOS.
- Để tìm hiểu thêm về cách làm việc với kho lưu trữ cục bộ và kho lưu trữ từ xa, hãy đọc về các phần phụ thuộc bên ngoài.
- Để tìm hiểu thêm về các quy tắc khác của Bazel, hãy xem hướng dẫn tham khảo này.
Chúc bạn tạo thành công!