Bazel hỗ trợ các phần phụ thuộc bên ngoài, tệp nguồn (cả văn bản và tệp nhị phân) được dùng trong bản dựng không phải từ không gian làm việc của bạn. Ví dụ: chúng có thể là một nhóm quy tắc được lưu trữ trong kho lưu trữ GitHub, một cấu phần phần mềm Maven hoặc một thư mục trên máy cục bộ bên ngoài không gian làm việc hiện tại của bạn.
Tài liệu này cung cấp thông tin tổng quan về hệ thống trước khi xem xét một số khái niệm chi tiết hơn.
Tổng quan về hệ thống
Hệ thống phần phụ thuộc bên ngoài của Bazel hoạt động dựa trên các mô-đun Bazel, mỗi mô-đun là một dự án Bazel có phiên bản và kho lưu trữ (hoặc kho lưu trữ), là các cây thư mục chứa tệp nguồn.
Bazel bắt đầu từ mô-đun gốc, tức là dự án mà bạn đang thực hiện.
Giống như mọi mô-đun, mô-đun này cần có một tệp MODULE.bazel
ở thư mục gốc, khai báo siêu dữ liệu cơ bản và các phần phụ thuộc trực tiếp. Sau đây là một ví dụ cơ bản:
module(name = "my-module", version = "1.0")
bazel_dep(name = "rules_cc", version = "0.1.1")
bazel_dep(name = "platforms", version = "0.0.11")
Từ đó, Bazel sẽ tra cứu tất cả các mô-đun phần phụ thuộc bắc cầu trong sổ đăng ký Bazel – theo mặc định là Sổ đăng ký trung tâm của Bazel. Sổ đăng ký cung cấp các tệp MODULE.bazel
của các phần phụ thuộc, cho phép Bazel khám phá toàn bộ biểu đồ phần phụ thuộc bắc cầu trước khi thực hiện việc phân giải phiên bản.
Sau khi phân giải phiên bản (trong đó một phiên bản được chọn cho mỗi mô-đun), Bazel sẽ tham khảo sổ đăng ký một lần nữa để tìm hiểu cách xác định một kho lưu trữ cho mỗi mô-đun, tức là cách tìm nạp các nguồn cho mỗi mô-đun phụ thuộc. Hầu hết các tệp này chỉ là những tệp lưu trữ được tải xuống từ Internet và trích xuất.
Các mô-đun cũng có thể chỉ định các phần dữ liệu tuỳ chỉnh được gọi là thẻ. Các thẻ này được tiện ích mô-đun sử dụng sau khi phân giải mô-đun để xác định các kho lưu trữ bổ sung. Các tiện ích này có thể thực hiện những thao tác như I/O tệp và gửi yêu cầu mạng. Ngoài những điều khác, các quy tắc này cho phép Bazel tương tác với các hệ thống quản lý gói khác, đồng thời tuân thủ biểu đồ phần phụ thuộc được tạo từ các mô-đun Bazel.
Ba loại kho lưu trữ (kho lưu trữ chính là cây nguồn mà bạn đang làm việc, kho lưu trữ đại diện cho các mô-đun phần phụ thuộc bắc cầu và kho lưu trữ do các tiện ích mô-đun tạo) tạo thành không gian làm việc cùng nhau.
Các kho lưu trữ bên ngoài (không phải kho lưu trữ chính) được tìm nạp theo yêu cầu, chẳng hạn như khi chúng được các nhãn tham chiếu (chẳng hạn như @repo//pkg:target
) trong tệp BUILD.
Lợi ích
Hệ thống phần phụ thuộc bên ngoài của Bazel mang lại nhiều lợi ích.
Tự động phân giải phần phụ thuộc
- Giải quyết phiên bản xác định: Bazel áp dụng thuật toán giải quyết phiên bản MVS xác định, giảm thiểu xung đột và giải quyết các vấn đề về phần phụ thuộc kim cương.
- Đơn giản hoá việc quản lý phần phụ thuộc:
MODULE.bazel
chỉ khai báo các phần phụ thuộc trực tiếp, trong khi các phần phụ thuộc bắc cầu sẽ được tự động phân giải, cung cấp thông tin tổng quan rõ ràng hơn về các phần phụ thuộc của dự án. - Chế độ hiển thị nghiêm ngặt của phần phụ thuộc: Chỉ các phần phụ thuộc trực tiếp mới hiển thị, đảm bảo tính chính xác và khả năng dự đoán.
Tích hợp hệ sinh thái
- Bazel Central Registry (Sổ đăng ký trung tâm của Bazel): Kho lưu trữ tập trung để khám phá và quản lý các phần phụ thuộc phổ biến dưới dạng mô-đun Bazel.
- Áp dụng các dự án không phải Bazel: Khi một dự án không phải Bazel (thường là thư viện C++) được điều chỉnh cho Bazel và có trong BCR, dự án đó sẽ đơn giản hoá quá trình tích hợp cho toàn bộ cộng đồng, đồng thời loại bỏ nỗ lực trùng lặp và xung đột của các tệp BUILD tuỳ chỉnh.
- Tích hợp thống nhất với các trình quản lý gói theo ngôn ngữ cụ thể: Ruleset giúp đơn giản hoá việc tích hợp với các trình quản lý gói bên ngoài cho các phần phụ thuộc không phải Bazel, bao gồm:
- rules_jvm_external cho Maven,
- rules_python cho PyPi,
- bazel-gazelle cho Mô-đun Go,
- rules_rust cho Cargo.
Tính năng nâng cao
- Tiện ích mô-đun: Các tính năng
use_repo_rule
và tiện ích mô-đun cho phép sử dụng linh hoạt các quy tắc kho lưu trữ tuỳ chỉnh và logic phân giải để giới thiệu mọi phần phụ thuộc không phải Bazel. bazel mod
Lệnh: Lệnh con này cung cấp những cách hiệu quả để kiểm tra các phần phụ thuộc bên ngoài. Bạn biết chính xác cách xác định một phần phụ thuộc bên ngoài và nguồn gốc của phần phụ thuộc đó.- Chế độ nhà cung cấp: Tìm nạp trước các phần phụ thuộc bên ngoài chính xác mà bạn cần để tạo điều kiện cho các bản dựng ngoại tuyến.
- Lockfile: Lockfile cải thiện khả năng tái tạo bản dựng và tăng tốc độ phân giải phần phụ thuộc.
- (Sắp ra mắt) Chứng thực nguồn gốc BCR: Tăng cường bảo mật chuỗi cung ứng bằng cách đảm bảo nguồn gốc đã xác minh của các phần phụ thuộc.
Khái niệm
Phần này cung cấp thêm thông tin chi tiết về các khái niệm liên quan đến các phần phụ thuộc bên ngoài.
Mô-đun
Một dự án Bazel có thể có nhiều phiên bản, mỗi phiên bản có thể có các phần phụ thuộc vào các mô-đun khác.
Trong không gian làm việc Bazel cục bộ, một mô-đun được biểu thị bằng một kho lưu trữ.
Để biết thêm thông tin, hãy xem phần Các mô-đun Bazel.
Kho lưu trữ
Một cây thư mục có tệp đánh dấu ranh giới ở gốc, chứa các tệp nguồn có thể dùng trong bản dựng Bazel. Thường được rút gọn thành repo.
Tệp đánh dấu ranh giới kho lưu trữ có thể là MODULE.bazel
(cho biết kho lưu trữ này đại diện cho một mô-đun Bazel), REPO.bazel
(xem bên dưới) hoặc trong các bối cảnh cũ, WORKSPACE
hoặc WORKSPACE.bazel
. Mọi tệp đánh dấu ranh giới kho lưu trữ sẽ biểu thị ranh giới của một kho lưu trữ; nhiều tệp như vậy có thể cùng tồn tại trong một thư mục.
Kho lưu trữ chính
Kho lưu trữ mà lệnh Bazel hiện tại đang chạy.
Thư mục gốc của kho lưu trữ chính còn được gọi là thư mục gốc của không gian làm việc.
Không gian làm việc
Môi trường được chia sẻ bởi tất cả các lệnh Bazel chạy trong cùng một kho lưu trữ chính. Nền tảng này bao gồm kho lưu trữ chính và tập hợp tất cả các kho lưu trữ bên ngoài đã xác định.
Xin lưu ý rằng trước đây, các khái niệm về "kho lưu trữ" và "không gian làm việc" đã bị lẫn lộn; thuật ngữ "không gian làm việc" thường được dùng để chỉ kho lưu trữ chính, và đôi khi thậm chí còn được dùng làm từ đồng nghĩa của "kho lưu trữ".
Tên kho lưu trữ chuẩn
Tên mà kho lưu trữ luôn có thể định địa chỉ. Trong bối cảnh của một không gian làm việc, mỗi kho lưu trữ có một tên chính tắc duy nhất. Một mục tiêu bên trong một kho lưu trữ có tên chính tắc là canonical_name
có thể được giải quyết bằng nhãn @@canonical_name//package:target
(lưu ý dấu @
kép).
Kho lưu trữ chính luôn có chuỗi trống làm tên chuẩn.
Tên kho lưu trữ rõ ràng
Tên mà một kho lưu trữ có thể định địa chỉ trong bối cảnh của một kho lưu trữ khác. Bạn có thể coi đây là "biệt hiệu" của một kho lưu trữ: Kho lưu trữ có tên chính tắc michael
có thể có tên hiển thị là mike
trong bối cảnh của kho lưu trữ alice
, nhưng có thể có tên hiển thị là mickey
trong bối cảnh của kho lưu trữ bob
. Trong trường hợp này, một đích đến bên trong michael
có thể được giải quyết bằng nhãn @mike//package:target
trong ngữ cảnh của alice
(lưu ý @
duy nhất).
Ngược lại, bạn có thể hiểu đây là một mối liên kết kho lưu trữ: mỗi kho lưu trữ duy trì một mối liên kết từ "tên kho lưu trữ hiển thị" đến "tên kho lưu trữ chuẩn".
Quy tắc kho lưu trữ
Một giản đồ cho các định nghĩa kho lưu trữ cho Bazel biết cách hiện thực hoá một kho lưu trữ. Ví dụ: đó có thể là "tải một tệp lưu trữ zip xuống từ một URL nhất định và trích xuất tệp đó", hoặc "tìm nạp một cấu phần phần mềm Maven nhất định và cung cấp cấu phần đó dưới dạng mục tiêu java_import
", hoặc đơn giản là "liên kết tượng trưng một thư mục cục bộ". Mọi kho lưu trữ đều được xác định bằng cách gọi một quy tắc kho lưu trữ với số lượng đối số thích hợp.
Hãy xem Quy tắc kho lưu trữ để biết thêm thông tin về cách viết quy tắc kho lưu trữ của riêng bạn.
Các quy tắc phổ biến nhất của repo cho đến nay là http_archive
, tải một kho lưu trữ xuống từ một URL và trích xuất kho lưu trữ đó, và local_repository
, liên kết tượng trưng một thư mục cục bộ đã là một kho lưu trữ Bazel.
Tìm nạp một kho lưu trữ
Thao tác cung cấp một kho lưu trữ trên ổ đĩa cục bộ bằng cách chạy quy tắc kho lưu trữ được liên kết. Các kho lưu trữ được xác định trong một không gian làm việc không có sẵn trên ổ đĩa cục bộ trước khi được tìm nạp.
Thông thường, Bazel chỉ tìm nạp một kho lưu trữ khi cần một nội dung nào đó trong kho lưu trữ đó và kho lưu trữ đó chưa được tìm nạp. Nếu trước đó bạn đã tìm nạp kho lưu trữ, Bazel sẽ chỉ tìm nạp lại nếu định nghĩa của kho lưu trữ đó đã thay đổi.
Bạn có thể dùng lệnh fetch
để bắt đầu tìm nạp trước cho một kho lưu trữ, mục tiêu hoặc tất cả các kho lưu trữ cần thiết để thực hiện bất kỳ bản dựng nào. Tính năng này cho phép tạo bản dựng ngoại tuyến bằng cách sử dụng lựa chọn --nofetch
.
Lựa chọn --fetch
dùng để quản lý quyền truy cập vào mạng. Giá trị mặc định của thuộc tính này là true.
Tuy nhiên, khi được đặt thành false (--nofetch
), lệnh sẽ sử dụng mọi phiên bản phụ thuộc được lưu vào bộ nhớ đệm và nếu không có phiên bản nào, lệnh sẽ dẫn đến lỗi.
Hãy xem các lựa chọn tìm nạp để biết thêm thông tin về cách kiểm soát hoạt động tìm nạp.
Bố cục thư mục
Sau khi được tìm nạp, bạn có thể tìm thấy kho lưu trữ trong thư mục con external
trong output base (cơ sở đầu ra), theo tên chính tắc của kho lưu trữ đó.
Bạn có thể chạy lệnh sau để xem nội dung của kho lưu trữ có tên chính tắc là canonical_name
:
ls $(bazel info output_base)/external/ canonical_name
Tệp REPO.bazel
Tệp REPO.bazel
được dùng để đánh dấu ranh giới trên cùng của cây thư mục tạo nên một kho lưu trữ. Không cần chứa bất kỳ nội dung nào để đóng vai trò là tệp ranh giới kho lưu trữ; tuy nhiên, bạn cũng có thể dùng tệp này để chỉ định một số thuộc tính chung cho tất cả các mục tiêu xây dựng bên trong kho lưu trữ.
Cú pháp của tệp REPO.bazel
tương tự như tệp BUILD
, ngoại trừ việc không hỗ trợ câu lệnh load
. Hàm repo()
nhận các đối số giống như hàm package()
trong các tệp BUILD
; trong khi package()
chỉ định các thuộc tính chung cho tất cả các mục tiêu xây dựng bên trong gói, thì repo()
cũng làm như vậy cho tất cả các mục tiêu xây dựng bên trong kho lưu trữ.
Ví dụ: bạn có thể chỉ định một giấy phép chung cho tất cả các mục tiêu trong kho lưu trữ bằng cách có tệp REPO.bazel
sau đây:
repo(
default_package_metadata = ["//:my_license"],
)
Hệ thống WORKSPACE cũ
Trong các phiên bản Bazel cũ (trước phiên bản 9.0), các phần phụ thuộc bên ngoài được giới thiệu bằng cách xác định các kho lưu trữ trong tệp WORKSPACE
(hoặc WORKSPACE.bazel
). Tệp này có cú pháp tương tự như tệp BUILD
, sử dụng các quy tắc kho lưu trữ thay vì các quy tắc bản dựng.
Đoạn mã sau đây là một ví dụ về cách sử dụng quy tắc kho lưu trữ http_archive
trong tệp WORKSPACE
:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "foo",
urls = ["https://example.com/foo.zip"],
sha256 = "c9526390a7cd420fdcec2988b4f3626fe9c5b51e2959f685e8f4d170d1a9bd96",
)
Đoạn mã này xác định một kho lưu trữ có tên chính tắc là foo
. Trong hệ thống WORKSPACE
, theo mặc định, tên chuẩn của một kho lưu trữ cũng là tên hiển thị của kho lưu trữ đó đối với tất cả các kho lưu trữ khác.
Xem danh sách đầy đủ các hàm có trong tệp WORKSPACE
.
Những điểm hạn chế của hệ thống WORKSPACE
Trong những năm sau khi hệ thống WORKSPACE
ra mắt, người dùng đã báo cáo nhiều điểm khó khăn, bao gồm:
- Bazel không đánh giá các tệp
WORKSPACE
của bất kỳ phần phụ thuộc nào, vì vậy, tất cả các phần phụ thuộc bắc cầu phải được xác định trong tệpWORKSPACE
của kho lưu trữ chính, ngoài các phần phụ thuộc trực tiếp. - Để khắc phục vấn đề này, các dự án đã áp dụng mẫu "deps.bzl", trong đó các dự án xác định một macro, macro này sẽ xác định nhiều kho lưu trữ và yêu cầu người dùng gọi macro này trong tệp
WORKSPACE
của họ.- Điều này có vấn đề riêng: macro không thể
load
các tệp.bzl
khác, vì vậy, các dự án này phải xác định các phần phụ thuộc bắc cầu trong macro "deps" này hoặc giải quyết vấn đề này bằng cách yêu cầu người dùng gọi nhiều macro "deps" theo lớp. - Bazel đánh giá tệp
WORKSPACE
theo tuần tự. Ngoài ra, các phần phụ thuộc được chỉ định bằnghttp_archive
với URL, không có thông tin phiên bản. Điều này có nghĩa là không có cách nào đáng tin cậy để thực hiện việc phân giải phiên bản trong trường hợp có các phần phụ thuộc dạng kim cương (A
phụ thuộc vàoB
vàC
;B
vàC
đều phụ thuộc vào các phiên bản khác nhau củaD
).
- Điều này có vấn đề riêng: macro không thể
Do những thiếu sót của WORKSPACE, hệ thống mới dựa trên mô-đun (có tên mã là "Bzlmod") đã dần thay thế hệ thống WORKSPACE cũ trong khoảng thời gian từ Bazel 6 đến 9. Đọc hướng dẫn di chuyển Bzlmod để biết cách di chuyển sang Bzlmod.