Mô-đun Bazel

Báo cáo vấn đề Xem nguồn Hằng đêm · 7,4 của Google. 7.3 · 7,2 · 7.1 · 7 · 6,5

Mô-đun Bazel là một dự án Bazel có thể có nhiều phiên bản, mỗi phiên bản phát hành 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 hộp Cargo.

Một mô-đun phải có tệp MODULE.bazel ở gốc kho lưu trữ. 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. 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")

Xem danh sách đầy đủ các lệnh có trong tệp MODULE.bazel.

Để thực hiện quá trình phân giải mô-đun, Bazel bắt đầu bằng cách đọc MODULE.bazel rồi liên tục yêu cầu bất kỳ phần phụ thuộc nào Tệp MODULE.bazel từ sổ đăng ký Bazel cho đến khi khám phá toàn bộ biểu đồ phần phụ thuộc.

Theo mặc định, Bazel sau đó 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 ý kiến đăng ký để 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 đồ tạo phiên bản. Phổ biến nhất cho đến nay là SemVer, nhưng cũng có các dự án nổi bật sử dụng các lược đồ khác nhau như Abseil, các phiên bản dựa trên ngày, ví dụ: 20210324.2).

Vì lý do này, Bzlmod sử dụng một phiên bản thoải mái hơn của thông số SemVer. Chiến lược phát hành đĩa đơn bao gồm:

  • SemVer quy định rằng "bản phát hành" Một phần của phiên bản phải bao gồm 3 ký tự phân khúc: MAJOR.MINOR.PATCH. Trong Bazel, yêu cầu này được nới lỏng để không giới hạn số lượng phân đoạn.
  • Trong SemVer, mỗi phân đoạn trong phần "bản phát hành" chỉ được chứa chữ số. Trong Bazel, chế độ này được nới lỏng để cho phép chữ cái cũng như phép so sánh ngữ nghĩa khớp với "mã nhận dạng" trong "bản thử nghiệm" phần.
  • Ngoài ra, ngữ nghĩa của việc tăng phiên bản chính, phiên bản phụ và phiên bản bản vá sẽ không được thực thi. Tuy nhiên, hãy xem mức độ tương thích để 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 Các phiên bản SemVer ab so sánh a < b khi và chỉ khi cùng một giữ nguyên 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 đề phần phụ thuộc kim cương, một vấn đề thường gặp trong không gian quản lý phần phụ thuộc 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

Tôi nên sử dụng phiên bản D nào? Để giải quyết câu hỏi 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ả các phiên bản của một mô-đun có khả năng tương thích ngược, nên hãy chọn phiên bản cao nhất do bất kỳ phần phụ thuộc nào chỉ định (trong ví dụ của chúng ta là D 1.1). Đó là "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 D 1.2 trở lên, chúng ta cũng không chọn biến thể đó. Việc sử dụng MVS sẽ tạo ra một quy trình lựa chọn phiên bản có độ chân thực caocó thể tái tạo.

Phiên bản đã Yanked

Registry có thể khai báo một số phiên bản nhất định là bị rút nếu bạn nên tránh 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 một lỗi khi chọn phiên bản đã bị xoá của một 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, không bị rút hoặc sử dụng cờ --allow_yanked_versions để cho phép rõ ràng phiên bản bị rút.

Mức độ tương thích

Trong Go, giả định của MVS về khả năng tương thích ngược có tác dụng vì nó xử lý các phiên bản tương thích ngược của một mô-đun dưới dạng một mô-đun riêng biệt. Xét về khía cạnh SemVer, tức là A 1.xA 2.x được xem là những 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, vì vậy, không có xung đột nào về thời gian biên dịch hoặc thời gian liên kết.

Tuy nhiên, Bazel không thể đưa ra những đảm bảo như vậy, vì vậy, Bazel 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 mức độ tương thích và được chỉ định bởi từng phiên bản mô-đun trong lệnh module(). Với thông tin này, Bazel có thể gửi lỗi khi phát hiện các phiên bản của cùng một mô-đun có mức độ tương thích khác nhau tồn tại trong biểu đồ phần phụ thuộc đã phân giải.

Ghi đè

Chỉ định các tuỳ chọn ghi đè trong tệp MODULE.bazel để thay đổi hành vi của độ 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 lượt 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 trong biểu đồ phần phụ thuộc. Mặc dù chỉ có phần ghi đè của mô-đun gốc chiếm chúng có thể là các phần phụ thuộc bắc cầu mà mô-đun gốc không có phụ thuộc trực tiếp.

Ghi đè cho một phiên bản

single_version_override phục vụ 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 bắt nguồn từ một sổ đăng ký cụ thể, thay vì tuân theo cơ quan quản lý thông thường chọn lọc.
  • Với các thuộc tính patch*, bạn có thể chỉ định một tập hợp bản vá để áp dụng cho mô-đun đã tải xuống.

Các thuộc tính này đều không bắt buộc và có thể kết hợp và so khớp với nhau.

Ghi đè nhiều phiên bản

multiple_version_override có thể được chỉ định để 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 danh sách rõ ràng các phiên bản được phép cho mô-đun. Danh sách này phải đều có trong biểu đồ phần phụ thuộc trước khi phân giải – phải có sẵn 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ỉ các phiên bản được phép của mô-đun 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 nào được phép cao hơn ở cùng cấp độ tương thích, thì Bazel sẽ gửi một lỗi.

Ví dụ: nếu các phiên bản 1.1, 1.3, 1.5, 1.72.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à khả năng tương thích cấp độ:

  • Việc ghi đè nhiều phiên bản cho phép 1.3, 1.72.0 sẽ dẫn đến việc 1.1 được nâng cấp lên 1.3, 1.5 được nâng cấp lên 1.7 và các phiên bản khác vẫn giữ nguyên.
  • Việc ghi đè nhiều phiên bản cho phép 1.52.0 sẽ dẫn đến lỗi, vì 1.7 không có phiên bản cao hơn ở cùng cấp độ tương thích để nâng cấp lên.
  • Việc ghi đè nhiều phiên bản cho phép 1.92.0 dẫn đến lỗi, vì 1.9 không xuất hiện 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ách ghi đè phiên bản đơn.

Thông tin thay thế không phải của tổ chức quản lý tên miền

Các cơ chế ghi đè không phải hệ thống đăng ký sẽ xoá hoàn toàn mô-đun khỏi độ phân giải phiên bản. Bazel không yêu cầu các tệp MODULE.bazel này từ sổ đăng ký, mà thay vào đó là từ chính kho lưu trữ.

Bazel hỗ trợ các chế độ ghi đè không phải sổ đăng ký sau:

Xác định các kho lưu trữ không đại diện cho các mô-đun Bazel

Với bazel_dep, bạn có thể xác định các kho lưu trữ đại diện cho các mô-đun Bazel khác. Đôi khi, bạn cần xác định một kho lưu trữ không đại diện cho Bazel module; ví dụ: một tệp chứa một tệp JSON thuần tuý sẽ được đọc dưới dạng dữ liệu.

Trong trường hợp này, bạn có thể sử dụng phương thức use_repo_rule lệnh để trực tiếp xác định một kho lưu trữ bằng cách gọi quy tắc repo. Kho lưu trữ này sẽ chỉ hiển thị với mô-đun được xác định trong đó.

Về cơ bản, tính năng này được triển khai bằng cách sử dụng cùng một cơ chế như tiện ích mô-đun, cho phép bạn xác định kho lưu trữ một cách linh hoạt hơn.

Tên kho lưu trữ và phần phụ thuộc nghiêm ngặt

Tên rõ ràng của kho lưu trữ sao lưu mặc định là tên mô-đun, trừ phi các phần phụ thuộc trực tiếp Thuộc tính repo_name của bazel_dep thì có nội dung 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 mô-đun đó. Điều này giúp ngăn chặn tình trạng gián đoạn ngoài ý muốn do các thay đổi trong phần phụ thuộc bắc cầu.

Tên chuẩn của kho lưu trữ sao lưu mô-đun là module_name+version (ví dụ: bazel_skylib+1.0.3) hoặc module_name+ (ví dụ: bazel_features+), tuỳ thuộc vào việc có nhiều phiên bản mô-đun trong toàn bộ biểu đồ phần phụ thuộc hay không (xem multiple_version_override). Xin lưu ý rằng định dạng tên chuẩn không phải là API mà bạn nên phụ thuộc vào và có thể thay đổi bất cứ lúc nào. Thay vì mã hoá cứng tên chính tắc, hãy sử dụng một cách được hỗ trợ để lấy tên đó trực tiếp từ Bazel: Trong các tệp BUILD và .bzl, hãy sử dụng Label.repo_name trên một thực thể Label được tạo từ một chuỗi nhãn do tên hiển thị của kho lưu trữ cung cấp, ví dụ: Label("@bazel_skylib").repo_name. * Khi tra cứu các tệp run, hãy sử dụng $(rlocationpath ...) hoặc một trong những thư viện runfile trong @bazel_tools//tools/{bash,cpp,java}/runfiles hoặc đối với bộ quy tắc rules_foo, trong @rules_foo//foo/runfiles. * Khi tương tác với Bazel từ một công cụ bên ngoài như IDE hoặc máy chủ ngôn ngữ, hãy sử dụng lệnh bazel mod dump_repo_mapping để ánh xạ từ tên hiển thị sang tên chuẩn cho một nhóm kho lưu trữ nhất định.

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ô-đun.