Mô-đun Bazel là một dự án Bazel có thể có nhiều phiên bản, mỗi phiên bản sẽ xuất bản siêu dữ liệu về các mô-đun khác mà nó phụ thuộc vào. Điều này tương tự như các khái niệm quen thuộc trong các hệ thống quản lý phần phụ thuộc khác, chẳng hạn như cấu phần phần mềm Maven, gói npm, mô-đun Go hoặc crate Cargo.
Một mô-đun phải có tệp MODULE.bazel
ở gốc kho lưu trữ (bên cạnh tệp WORKSPACE
). Tệp này là tệp kê khai của mô-đun, khai báo tên, phiên bản, danh sách các phần phụ thuộc trực tiếp và thông tin khác của mô-đun. Ví dụ cơ bản:
module(name = "my-module", version = "1.0")
bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep
(name = "protobuf", version = "3.19.0")
Để thực hiện phân giải mô-đun, Bazel bắt đầu bằng cách đọc tệp MODULE.bazel
của mô-đun gốc, rồi liên tục yêu cầu tệp MODULE.bazel
của mọi phần phụ thuộc từ sổ đăng ký Bazel cho đến khi phát hiện ra toàn bộ biểu đồ phần phụ thuộc.
Theo mặc định, Bazel sẽ chọn một phiên bản của mỗi mô-đun để sử dụng. Bazel đại diện cho mỗi mô-đun bằng một kho lưu trữ và tham khảo sổ đăng ký một lần nữa để tìm hiểu cách xác định từng kho lưu trữ.
Định dạng phiên bản
Bazel có một hệ sinh thái đa dạng và các dự án sử dụng nhiều lược đồ quản lý phiên bản. SemVer là lược đồ phổ biến nhất cho đến nay, nhưng cũng có những dự án nổi bật sử dụng các lược đồ khác, chẳng hạn như Abseil. Các phiên bản của dự án này dựa trên ngày, ví dụ: 20210324.2
.
Vì lý do này, Bzlmod áp dụng một phiên bản thoải mái hơn của quy cách SemVer. Các điểm khác biệt bao gồm:
- SemVer quy định rằng phần "release" (phát hành) của phiên bản phải bao gồm 3 phân đoạn:
MAJOR.MINOR.PATCH
. Trong Bazel, yêu cầu này được nới lỏng để cho phép sử dụng bất kỳ số lượng phân đoạn nào. - Trong SemVer, mỗi phân đoạn trong phần "bản phát hành" chỉ được chứa các chữ số. Trong Bazel, quy tắc này được nới lỏng để cho phép cả chữ cái, đồng thời ngữ nghĩa so sánh sẽ khớp với "mã nhận dạng" trong phần "phát hành trước".
- Ngoài ra, ngữ nghĩa của việc tăng phiên bản chính, phụ và bản vá không được thực thi. Tuy nhiên, hãy xem cấp độ tương thích để biết thông tin chi tiết về cách chúng tôi biểu thị khả năng tương thích ngược.
Mọi phiên bản SemVer hợp lệ đều là phiên bản mô-đun Bazel hợp lệ. Ngoài ra, hai phiên bản SemVer a
và b
so sánh a < b
nếu và chỉ khi điều tương tự xảy ra khi chúng được so sánh dưới dạng các phiên bản mô-đun Bazel.
Chọn phiên bản
Hãy xem xét vấn đề về phần phụ thuộc hình kim cương, một vấn đề thường gặp trong không gian quản lý phần phụ thuộc theo phiên bản. Giả sử bạn có biểu đồ phần phụ thuộc:
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
Bạn nên dùng phiên bản D
nào? Để giải quyết vấn đề này, Bzlmod sử dụng thuật toán Lựa chọn phiên bản tối thiểu (MVS) được giới thiệu trong hệ thống mô-đun Go. MVS giả định rằng tất cả phiên bản mới của một mô-đun đều tương thích ngược, do đó, MVS sẽ chọn phiên bản cao nhất do bất kỳ thành phần phụ thuộc nào chỉ định (D 1.1
trong ví dụ của chúng ta). Đây là phiên bản "tối thiểu" vì D 1.1
là phiên bản sớm nhất có thể đáp ứng các yêu cầu của chúng tôi – ngay cả khi có phiên bản D 1.2
hoặc mới hơn, chúng tôi cũng không chọn. Việc sử dụng MVS sẽ tạo ra một quy trình chọn phiên bản có độ trung thực cao và có thể tái tạo.
Các phiên bản bị rút lại
Sổ đăng ký có thể khai báo một số phiên bản nhất định là bị rút lại nếu bạn nên tránh dùng các phiên bản đó (chẳng hạn như đối với các lỗ hổng bảo mật). Bazel sẽ gửi lỗi khi chọn một phiên bản bị rút lại của mô-đun. Để khắc phục lỗi này, hãy nâng cấp lên phiên bản mới hơn, chưa bị rút lại hoặc sử dụng cờ --allow_yanked_versions
để cho phép rõ ràng phiên bản bị rút lại.
Mức độ tương thích
Trong Go, giả định của MVS về khả năng tương thích ngược hoạt động vì nó coi các phiên bản không tương thích ngược của một mô-đun là một mô-đun riêng biệt. Về SemVer, điều đó có nghĩa là A 1.x
và A 2.x
được coi là các mô-đun riêng biệt và có thể cùng tồn tại trong biểu đồ phần phụ thuộc đã phân giải. Đổi lại, điều này có thể thực hiện được bằng cách mã hoá phiên bản chính trong đường dẫn gói trong Go, nên sẽ không có xung đột nào trong thời gian biên dịch hoặc thời gian liên kết.
Tuy nhiên, Bazel không thể đảm bảo điều đó, nên cần số "phiên bản chính" để phát hiện các phiên bản không tương thích ngược. Số này được gọi là cấp độ tương thích và do mỗi phiên bản mô-đun chỉ định trong chỉ thị module()
. Với thông tin này, Bazel có thể đưa ra lỗi khi phát hiện thấy các phiên bản của cùng một mô-đun có các cấp độ tương thích khác nhau trong biểu đồ phần phụ thuộc đã phân giải.
Ghi đè
Chỉ định các chế độ ghi đè trong tệp MODULE.bazel
để thay đổi hành vi của quá trình phân giải mô-đun Bazel. Chỉ các chế độ ghi đè của mô-đun gốc mới có hiệu lực – nếu một mô-đun được dùng làm phần phụ thuộc, thì các chế độ ghi đè của mô-đun đó sẽ bị bỏ qua.
Mỗi chế độ ghi đè được chỉ định cho một tên mô-đun nhất định, ảnh hưởng đến tất cả các phiên bản của mô-đun đó trong biểu đồ phần phụ thuộc. Mặc dù chỉ các chế độ ghi đè của mô-đun gốc mới có hiệu lực, nhưng chúng có thể dành cho các phần phụ thuộc bắc cầu mà mô-đun gốc không phụ thuộc trực tiếp vào.
Ghi đè một phiên bản
single_version_override
có nhiều mục đích:
- Với thuộc tính
version
, bạn có thể ghim một phần phụ thuộc vào một phiên bản cụ thể, bất kể phiên bản nào của phần phụ thuộc được yêu cầu trong biểu đồ phần phụ thuộc. - Với thuộc tính
registry
, bạn có thể buộc phần phụ thuộc này đến từ một sổ đăng ký cụ thể, thay vì tuân theo quy trình chọn sổ đăng ký thông thường. - Với các thuộc tính
patch*
, bạn có thể chỉ định một nhóm bản vá để áp dụng cho mô-đun đã tải xuống.
Tất cả các thuộc tính này đều không bắt buộc và có thể kết hợp với nhau.
Ghi đè nhiều phiên bản
Bạn có thể chỉ định một multiple_version_override
để cho phép nhiều phiên bản của cùng một mô-đun cùng tồn tại trong biểu đồ phần phụ thuộc đã phân giải.
Bạn có thể chỉ định một danh sách rõ ràng gồm các phiên bản được phép cho mô-đun. Tất cả các phiên bản này phải có trong biểu đồ phần phụ thuộc trước khi phân giải – phải có một số phần phụ thuộc bắc cầu tuỳ thuộc vào từng phiên bản được phép. Sau khi phân giải, chỉ những phiên bản được phép của mô-đun mới còn lại, trong khi Bazel nâng cấp các phiên bản khác của mô-đun lên phiên bản được phép cao hơn gần nhất ở cùng cấp độ tương thích. Nếu không có phiên bản được phép nào cao hơn ở cùng cấp độ tương thích, Bazel sẽ báo lỗi.
Ví dụ: nếu các phiên bản 1.1
, 1.3
, 1.5
, 1.7
và 2.0
tồn tại trong biểu đồ phần phụ thuộc trước khi phân giải và phiên bản chính là cấp độ tương thích:
- Một chế độ ghi đè nhiều phiên bản cho phép
1.3
,1.7
và2.0
dẫn đến việc1.1
được nâng cấp lên1.3
,1.5
được nâng cấp lên1.7
và các phiên bản khác vẫn giữ nguyên. - Một chế độ ghi đè nhiều phiên bản cho phép
1.5
và2.0
dẫn đến lỗi, vì1.7
không có phiên bản nào cao hơn ở cùng cấp độ tương thích để nâng cấp. - Một chế độ ghi đè nhiều phiên bản cho phép
1.9
và2.0
dẫn đến lỗi, vì1.9
không có trong biểu đồ phần phụ thuộc trước khi phân giải.
Ngoài ra, người dùng cũng có thể ghi đè sổ đăng ký bằng thuộc tính registry
, tương tự như các chế độ ghi đè một phiên bản.
Ghi đè không đăng ký
Các chế độ ghi đè không đăng ký sẽ xoá hoàn toàn một mô-đun khỏi quá trình phân giải phiên bản. Bazel không yêu cầu các tệp MODULE.bazel
này từ một sổ đăng ký, mà là từ chính kho lưu trữ.
Bazel hỗ trợ các chế độ ghi đè không đăng ký sau:
Tên kho lưu trữ và các phần phụ thuộc nghiêm ngặt
Tên chính tắc của một kho lưu trữ hỗ trợ một mô-đun là module_name~version
(ví dụ: bazel_skylib~1.0.3
). Đối với các mô-đun có chế độ ghi đè không đăng ký, hãy thay thế phần version
bằng chuỗi override
. Xin lưu ý rằng định dạng tên chuẩn không phải là một API mà bạn nên phụ thuộc vào và có thể thay đổi bất cứ lúc nào.
Tên hiển thị của một kho lưu trữ hỗ trợ một mô-đun cho các phần phụ thuộc trực tiếp của mô-đun đó sẽ mặc định là tên mô-đun, trừ phi thuộc tính repo_name
của chỉ thị bazel_dep
có quy định khác. Xin lưu ý rằng điều này có nghĩa là một mô-đun chỉ có thể tìm thấy các phần phụ thuộc trực tiếp của nó. Điều này giúp ngăn chặn tình trạng gián đoạn do vô tình vì những thay đổi trong các phần phụ thuộc bắc cầu.
Tiện ích mô-đun cũng có thể đưa các kho lưu trữ bổ sung vào phạm vi hiển thị của một mô-đun.