Tổng quan về các phần phụ thuộc bên ngoài

Báo cáo vấn đề Xem nguồn Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bazel hỗ trợ các phần phụ thuộc bên ngoài, các tệp nguồn (cả văn bản và tệp nhị phân) được sử 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ụ: đó có thể là một bộ quy tắc được lưu trữ trong kho lưu trữ GitHub, cấu phần phần mềm Maven hoặc thư mục trên máy cục bộ của bạn bên ngoài không gian làm việc hiện tại.

Kể từ Bazel 6.0, có hai cách để quản lý các phần phụ thuộc bên ngoài bằng Bazel: hệ thống WORKSPACE truyền thống, tập trung vào kho lưu trữ và hệ thống MODULE.bazel mới hơn, tập trung vào mô-đun (có tên mã là Bzlmod và được bật bằng cờ --enable_bzlmod). Bạn có thể sử dụng cả hai hệ thống này, nhưng Bzlmod sẽ thay thế hệ thống WORKSPACE trong các bản phát hành Bazel trong tương lai. Hãy xem hướng dẫn di chuyển Bzlmod để biết cách di chuyển.

Tài liệu này giải thích các khái niệm liên quan đến việc quản lý phần phụ thuộc bên ngoài trong Bazel, trước khi đi sâu vào chi tiết hơn về hai hệ thống theo thứ tự.

Khái niệm

Kho lưu trữ

Cây thư mục có tệp điểm đánh dấu ranh giới ở thư mục 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 của kho lưu trữ có thể là MODULE.bazel (báo hiệu rằng kho lưu trữ này đại diện cho mô-đun Bazel), REPO.bazel (xem bên dưới) hoặc trong ngữ cảnh cũ, WORKSPACE hoặc WORKSPACE.bazel. Mọi tệp đánh dấu ranh giới repo 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ữ đang chạy lệnh Bazel hiện tại.

Phần gốc của kho lưu trữ chính còn được gọi là gốc không gian làm việc.

Workspace

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. Thư mục này bao gồm kho lưu trữ chính và tập hợp tất 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 "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 chuẩn hoá mà một kho lưu trữ có thể được định địa chỉ. Trong bối cảnh 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. Bạn có thể nhắm mục tiêu bên trong một kho lưu trữ có tên chuẩn là canonical_name bằng nhãn @@canonical_name//package:target (lưu ý @ kép).

Kho lưu trữ chính luôn sử dụng chuỗi trống làm tên chuẩn.

Tên kho lưu trữ hiển thị

Tên của một kho lưu trữ có thể được định địa chỉ trong ngữ 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 kho lưu trữ: Kho lưu trữ có tên chuẩn hoá michael có thể có tên hiển thị là mike trong ngữ cảnh của kho lưu trữ alice, nhưng có thể có tên hiển thị là mickey trong ngữ cảnh của kho lưu trữ bob. Trong trường hợp này, nhãn @mike//package:target có thể xử lý một mục tiêu bên trong michael trong ngữ cảnh của alice (lưu ý @ đơn).

Ngược lại, bạn có thể hiểu đây là một lớp ánh xạ kho lưu trữ: mỗi kho lưu trữ duy trì một lớp ánh xạ 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ữ

Giản đồ cho các định nghĩa về kho lưu trữ cho Bazel biết cách hiện thực hoá một kho lưu trữ. Ví dụ: thao tác này có thể là "tải một tệp lưu trữ zip xuống từ một URL nhất định và giải nén 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 phần mềm đó dưới dạng mục tiêu java_import" hoặc chỉ đơ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ữ đượ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 phần 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.

Cho đến nay, các quy tắc kho lưu trữ phổ biến nhất là http_archive, giúp tải một tệp lưu trữ xuống từ một URL và trích xuất tệp lưu trữ đó, cũng như local_repository, giúp liên kết tượng trưng một thư mục cục bộ đã là kho lưu trữ Bazel.

Tìm nạp kho lưu trữ

Thao tác cung cấp kho lưu trữ trên ổ đĩa cục bộ bằng cách chạy quy tắc kho lưu trữ 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 thứ gì đó từ kho lưu trữ đó và kho lưu trữ đó chưa được tìm nạp. Nếu đã tìm nạp kho lưu trữ trước đó, thì Bazel 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ả kho lưu trữ cần thiết để thực hiện bất kỳ bản dựng nào. Khả năng này cho phép tạo bản dựng ngoại tuyến bằng tuỳ chọn --nofetch.

Tuỳ chọn --fetch dùng để quản lý quyền truy cập mạng. Giá trị mặc định của giá trị này là true. Tuy nhiên, khi được đặt thành false (--nofetch), lệnh này sẽ sử dụng mọi phiên bản phầ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 này sẽ dẫn đến lỗi.

Hãy xem các tuỳ chọn tìm nạp để biết thêm thông tin về cách kiểm soát tính nă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ữ này trong thư mục con external trong cơ sở đầu ra, theo tên chuẩn 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 chuẩn 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ữ. Tệp này không cần chứa bất kỳ nội dung nào để phân phát dưới dạng tệp ranh giới kho lưu trữ; tuy nhiên, bạn cũng có thể sử dụng tệp này để chỉ định một số thuộc tính phổ biến cho tất cả các mục tiêu bản 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 và chỉ có một hàm duy nhất là repo(). repo() sử dụng các đối số giống như hàm package() trong tệp BUILD; trong khi package() chỉ định các thuộc tính chung cho tất cả mục tiêu bản dựng bên trong gói, thì repo() cũng làm tương tự cho tất cả mục tiêu bản 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:

repo(
    default_package_metadata = ["//:my_license"],
)

Quản lý các phần phụ thuộc bên ngoài bằng Bzlmod

Bzlmod (hệ thống con mới của phần phụ thuộc bên ngoài) không trực tiếp hoạt động với các định nghĩa kho lưu trữ. Thay vào đó, công cụ này tạo một biểu đồ phần phụ thuộc từ các mô-đun, chạy các tiện ích trên biểu đồ và xác định kho lưu trữ tương ứng.

Mô-đun Bazel là một dự án Bazel có thể có nhiều phiên bản, trong đó 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. Mô-đun phải có tệp MODULE.bazel ở thư mục gốc của 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 phần phụ thuộc, cùng với các thông tin khác. Sau đây là một 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")

Mô-đun chỉ được liệt kê các phần phụ thuộc trực tiếp mà Bzlmod tra cứu trong một cơ sở đăng ký Bazel – theo mặc định là Cơ sở đăng ký trung tâm 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 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 lại sổ đăng ký để tìm hiểu cách xác định kho lưu trữ cho mỗi mô-đun (trong hầu hết các trường hợp, sử dụng http_archive).

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 phần dữ liệu 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ó chức năng tương tự như quy tắc của kho lưu trữ, cho phép thực hiện các thao tác như I/O tệp và gửi yêu cầu mạng. Ngoài ra, các mô-đun 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 theo biểu đồ phần phụ thuộc được tạo từ các mô-đun Bazel.

Xác định kho lưu trữ bằng WORKSPACE

Trước đây, bạn có thể quản lý các phần phụ thuộc bên ngoài bằng cách xác định kho lưu trữ trong tệp WORKSPACE (hoặc WORKSPACE.bazel). Tệp này có cú pháp tương tự như các 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à 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 chính tắc 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.

Điểm yếu của hệ thống WORKSPACE

Trong những năm kể từ khi hệ thống WORKSPACE được giới thiệu, người dùng đã báo cáo nhiều điểm yếu, bao gồm:

  • Bazel không đánh giá tệp WORKSPACE của bất kỳ phần phụ thuộc nào, vì vậy, ngoài các phần phụ thuộc trực tiếp, bạn phải xác định tất cả các phần phụ thuộc bắc cầu trong tệp WORKSPACE của kho lưu trữ chính.
  • Để giải quyết vấn đề này, các dự án đã sử dụng mẫu "deps.bzl", trong đó, các dự án xác định một macro 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.
    • Điều này cũng có vấn đề riêng: các 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 "phần phụ thuộc" 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 "phần phụ thuộc" 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ằng http_archive với URL mà không có bất kỳ thông tin phiên bản nào. Đ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 phần phụ thuộc kim cương (A phụ thuộc vào BC; cả BC phụ thuộc vào các phiên bản khác nhau của D).

Do những thiếu sót của WORKSPACE, Bzlmod sẽ thay thế hệ thống WORKSPACE cũ trong các bản phát hành Bazel trong tương lai. Vui lòng đọc Hướng dẫn di chuyển sang Bzlmod để biết cách di chuyển sang Bzlmod.