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 đầu tiên này để biết hướng dẫn đơn giản về cách sử dụng Bazel. Hướng dẫn này xác định các thuật ngữ chính khi chúng được sử dụng trong ngữ cảnh của Bazel và hướng dẫn bạn về các kiến thức cơ bản của quy trình công việc Bazel. Bắt đầu với các công cụ cần thiết, bạn sẽ tạo và chạy 3 giai đoạn các dự án ngày càng phức tạp hơn và tìm hiểu cách thức cũng như lý do khiến chúng 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 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 ước tính: 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 rồi. 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 cài đặt Git dưới dạng tốt.
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 sau đây trong công cụ dòng lệnh mà bạn chọn:
git clone https://github.com/bazelbuild/examples
Dự án mẫu cho hướng dẫn này nằm trong thư mục examples/cpp-tutorial
.
Hãy xem phần dưới đây để biết cấu trúc của chiến dịch:
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
Có ba nhóm tệp, mỗi nhóm đại diện cho một giai đoạn trong hướng dẫn này. Ở 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ẽ bạn sẽ tạo cả tệp nhị phân và thư viện từ một gói duy nhất. Ngang bằng giai đoạn thứ ba và cuối cùng là tạo một dự án có nhiều gói và hãy xây dựng chiến lược đó với nhiều mục tiêu.
Tóm tắt: Giới thiệu
Bằng cách cài đặt Bazel (và Git) và nhân bản 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 của mình bằng Bazel. Hãy 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
Thiết lập không gian làm việc
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 của 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. Nó cũng chứa các tệp quan trọng sau:
giúp xác định thư mục và nội dung trong thư mục là một không gian làm việc Bazel và nằm ở gốc cấu trúc thư mục của dự án.WORKSPACE
file- Một hoặc nhiều
cho Bazel biết cách tạo các phần khác nhau của dự án. Đáp trong không gian làm việc chứa tệpBUILD
filesBUILD
là một gói. (Thông tin khác về các gói ở phần sau của hướng dẫn này).
Trong các dự án trong tương lai, để chỉ định một thư mục làm không gian làm việc Bazel, hãy tạo một
tệp trống có tên WORKSPACE
trong thư mục đó. Trong phạm vi của hướng dẫn này,
một tệp WORKSPACE
đã có trong mỗi giai đoạn.
LƯU Ý: Khi Bazel tạo dự án, tất cả dữ liệu đầu vào phải nằm trong cùng một không gian làm việc. Các tệp nằm trong các không gian làm việc khác nhau sẽ độc lập với nhau trừ khi được liên kết. Bạn có thể tìm thêm thông tin chi tiết về quy tắc của không gian làm việc trong hướng dẫn này.
Tìm hiểu về tệp BUILD
Tệp BUILD
chứa một số loại hướng dẫn khác nhau cho Bazel. Mỗi tệp BUILD
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 ra kết quả mong muốn, chẳng hạn như các tệp nhị phân hoặc thư viện có thể thực thi. Mỗi thực thể của quy tắc bản dựng trong tệp BUILD
được gọi là mục tiêu và trỏ đến một nhóm tệp nguồn và phần phụ thuộc cụ thể.
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ụ này, mục tiêu hello-world
tạo thực thể của hàm tích hợp sẵn của Bazel
cc_binary rule
.
Quy tắc này yêu cầu Bazel tạo một tệp nhị phân thực thi độc lập từ
Tệp nguồn hello-world.cc
không có phần phụ thuộc.
Tóm tắt: bắt đầu
Giờ đây, bạn đã nắm được một số thuật ngữ chính và ý nghĩa của các thuật ngữ đó trong dự án này và nói chung là Bazel. Trong phần tiếp theo, bạn sẽ xây dựng 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 xây dựng 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
└── WORKSPACE
Chạy lệnh sau để chuyển đến thư mục cpp-tutorial/stage1
:
cd cpp-tutorial/stage1
Tiếp theo, hãy chạy:
bazel build //main:hello-world
Trong nhãn đích, phần //main:
là vị trí của tệp BUILD
tương ứng 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 thành phần có dạng 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 của mình. Bazel đặt kết quả của bản dựng trong
Thư mục bazel-bin
ở gốc của phần tử
Workspace.
Bây giờ, hãy kiểm thử tệp nhị phân được tạo mới, đó là:
bazel-bin/main/hello-world
Thao tác này sẽ in ra thông báo "Hello world
".
Sau đây là biểu đồ phần phụ thuộc của Giai đoạn 1:
Tóm tắt: giai đoạn 1
Giờ đây, khi đã hoàn thành bản dựng đầu tiên, bạn có ý tưởng cơ bản về cách tạo có cấu trúc. Ở 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 nê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 các 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 cá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 mà bạn đang xử lý cho Giai đoạn 2:
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── WORKSPACE
Hãy xem tệp BUILD
trong thư mục cpp-tutorial/stage2/main
bên dưới:
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, trước tiên Bazel sẽ tạo thư viện hello-greet
(sử dụng cc_library rule
tích hợp sẵn của Bazel),
rồi đến 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 hello-greet
cần có thư viện để tạo tệp nhị phân hello-world
.
Trước khi xây dựng phiên bản mới này của dự án, bạn cần thay đổi
các thư mục, chuyển sang thư mục cpp-tutorial/stage2
bằng cách chạy:
cd ../stage2
Bâ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-world
Một lần nữa, Bazel sẽ tạo ra một kết quả 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 được tạo mới và trả về một “Hello world
” khác:
bazel-bin/main/hello-world
Nế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 đầu vào tương tự như trước đây, nhưng cấu trúc của bản dựng lại khác:
Tóm tắt: giai đoạn 2
Lúc này, bạn đã xây dựng dự án với hai 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 thêm hai tệp nguồn. Trong phần tiếp theo, hãy tiến thêm một bước
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 chức năng 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 phần dưới đây
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
└── WORKSPACE
Bạn có thể thấy rằng hiện có hai thư mục con và mỗi thư mục chứa một tệp BUILD
. Do đó, đối với Bazel, không gian làm việc hiện chứa hai 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ại 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 đó có nhãn mục tiêu //lib:hello-time
) – Bazel biết
thao tác 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:
Để tạo bản dựng thành công, bạn cần đặt mục tiêu //lib:hello-time
trong lib/BUILD
hiển thị rõ ràng cho các mục tiêu trong main/BUILD
bằng thuộc tính chế độ hiển thị.
Điều này là do theo mặc định, các mục tiêu chỉ hiển thị với các mục tiêu khác trong cùng
Tệp BUILD
. Bazel sử dụng chế độ hiển thị mục tiêu để ngă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 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
bằng cách chạy:
cd ../stage3
Một lần nữa, hãy chạy lệnh sau:
bazel build //main:hello-world
Bazel tạo ra thành phần có dạng 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 tra tệp nhị phân cuối cùng của hướng dẫn này để biết thông báo Hello world
cuối cùng:
bazel-bin/main/hello-world
Tóm tắt: giai đoạn 3
Giờ đây, bạn đã tạo dự án dưới dạng hai gói với ba mục tiêu và hiểu rõ các phần phụ thuộc giữa các gói đó. Đ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 sử dụng Bazel.
Các bước tiếp theo
Giờ đây, bạn đã hoàn tất bản dựng cơ bản đầu tiên bằng Bazel, nhưng đây mới chỉ là bước khởi đầu. Dưới đây là một số tài nguyên khác để bạn 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 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à từ xa, hãy đọc bài viết về 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 dựng thành công!