Bazel có thể phụ thuộc vào các mục tiêu của các dự án khác. Các phần phụ thuộc từ các dự án khác này được gọi là phần phụ thuộc bên ngoài.
Tệp WORKSPACE
(hoặc tệp WORKSPACE.bazel
) trong
thư mục không gian làm việc
cho Bazel biết cách lấy nguồn của các dự án khác. Các dự án khác này có thể
chứa một hoặc nhiều tệp BUILD
với mục tiêu riêng. Các tệp BUILD
trong dự án chính có thể phụ thuộc vào các mục tiêu bên ngoài này bằng cách sử dụng tên của các tệp đó trong tệp WORKSPACE
.
Ví dụ: giả sử có hai dự án trên một hệ thống:
/
home/
user/
project1/
WORKSPACE
BUILD
srcs/
...
project2/
WORKSPACE
BUILD
my-libs/
Nếu project1
muốn phụ thuộc vào một mục tiêu, :foo
, được xác định trong
/home/user/project2/BUILD
, thì mục này có thể chỉ định rằng hệ thống có thể tìm thấy kho lưu trữ có tên
project2
tại /home/user/project2
. Sau đó, các mục tiêu trong
/home/user/project1/BUILD
có thể phụ thuộc vào @project2//:foo
.
Tệp WORKSPACE
cho phép người dùng phụ thuộc vào mục tiêu từ các phần khác của hệ thống tệp hoặc được tải xuống từ Internet. Nó sử dụng cú pháp giống như tệp BUILD
, nhưng cho phép một bộ quy tắc khác được gọi là quy tắc kho lưu trữ (đôi khi còn được gọi là quy tắc không gian làm việc). Bazel đi kèm với một số quy tắc kho lưu trữ tích hợp sẵn và một bộ quy tắc kho lưu trữ Starlark được nhúng.
Người dùng cũng có thể viết các quy tắc lưu trữ tuỳ chỉnh
để có được hành vi phức tạp hơn.
Các loại phần phụ thuộc bên ngoài được hỗ trợ
Có thể sử dụng một số loại phần phụ thuộc bên ngoài cơ bản:
- Phần phụ thuộc vào các dự án Bazel khác
- Phần phụ thuộc đối với các dự án không phải Brazil
- Phần phụ thuộc trên các gói bên ngoài
Tuỳ thuộc vào các dự án Bazel khác
Nếu muốn sử dụng các mục tiêu từ một dự án Bazel thứ hai, bạn có thể sử dụng local_repository
, git_repository
hoặc http_archive
để liên kết tượng trưng từ hệ thống tệp cục bộ, tham chiếu kho lưu trữ git hoặc tải xuống (tương ứng).
Ví dụ: giả sử bạn đang làm việc trong một dự án, my-project/
và bạn muốn
phụ thuộc vào các mục tiêu từ dự án của đồng nghiệp coworkers-project/
. Cả hai dự án đều sử dụng Bazel, vì vậy, bạn có thể thêm dự án của đồng nghiệp làm phần phụ thuộc bên ngoài, sau đó sử dụng bất kỳ mục tiêu nào mà đồng nghiệp đã xác định từ các tệp Builder của riêng bạn. Bạn sẽ thêm đoạn mã sau vào my_project/WORKSPACE
:
local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
)
Nếu đồng nghiệp của bạn có //foo:bar
mục tiêu, thì dự án có thể gọi dự án này là
@coworkers_project//foo:bar
. Tên dự án bên ngoài phải là tên không gian làm việc hợp lệ.
Tuỳ thuộc vào các dự án không phải Brazil
Các quy tắc có tiền tố new_
, chẳng hạn như new_local_repository
, cho phép bạn tạo mục tiêu từ các dự án không sử dụng Bazel.
Ví dụ: giả sử bạn đang làm việc trong một dự án, my-project/
và bạn muốn phụ thuộc vào dự án của đồng nghiệp coworkers-project/
. Dự án của đồng nghiệp của bạn sử dụng make
để tạo, nhưng bạn muốn phụ thuộc vào một trong các tệp .so mà dự án tạo ra. Để thực hiện việc này, hãy thêm nội dung sau vào my_project/WORKSPACE
:
new_local_repository(
name = "coworkers_project",
path = "/path/to/coworkers-project",
build_file = "coworker.BUILD",
)
build_file
chỉ định một tệp BUILD
để phủ lên dự án hiện có, ví dụ:
cc_library(
name = "some-lib",
srcs = glob(["**"]),
visibility = ["//visibility:public"],
)
Sau đó, bạn có thể phụ thuộc vào @coworkers_project//:some-lib
trong các tệp BUILD
của dự án.
Tuỳ thuộc vào các gói bên ngoài
Kho lưu trữ và cấu phần phần mềm Maven
Sử dụng bộ quy tắc rules_jvm_external
để tải các cấu phần phần mềm xuống từ kho lưu trữ Maven và cung cấp các cấu phần đó dưới dạng phần phụ thuộc
Java.
Tìm nạp phần phụ thuộc
Theo mặc định, các phần phụ thuộc bên ngoài sẽ được tìm nạp khi cần trong bazel build
. Nếu bạn muốn tìm nạp trước các phần phụ thuộc cần thiết cho một nhóm mục tiêu cụ thể, hãy sử dụng bazel fetch
.
Để tìm nạp vô điều kiện tất cả phần phụ thuộc bên ngoài, hãy sử dụng bazel sync
.
Khi kho lưu trữ được tìm nạp được lưu trữ trong cơ sở dữ liệu đầu ra, quá trình tìm nạp sẽ diễn ra trên mỗi không gian làm việc.
Phần phụ thuộc bóng
Bất cứ khi nào có thể, bạn nên có một chính sách phiên bản duy nhất trong dự án. Đây là yêu cầu bắt buộc đối với các phần phụ thuộc mà bạn biên dịch và kết thúc trong tệp nhị phân cuối cùng. Tuy nhiên, trong trường hợp không đúng, bạn có thể ẩn các phần phụ thuộc. Hãy xem xét trường hợp sau:
dự án/không gian làm việc của tôi
workspace(name = "myproject")
local_repository(
name = "A",
path = "../A",
)
local_repository(
name = "B",
path = "../B",
)
A/WORKSPACE
workspace(name = "A")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner",
urls = ["https://github.com/testrunner/v1.zip"],
sha256 = "...",
)
B/WORKSPACE
workspace(name = "B")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner",
urls = ["https://github.com/testrunner/v2.zip"],
sha256 = "..."
)
Cả hai phần phụ thuộc A
và B
đều phụ thuộc vào testrunner
, nhưng chúng phụ thuộc vào các phiên bản testrunner
khác nhau. Không có lý do để các trình chạy kiểm thử này không cùng tồn tại một cách yên bình trong myproject
, nhưng chúng sẽ xung đột với nhau vì chúng có cùng tên. Để khai báo cả hai phần phụ thuộc, hãy cập nhật myproject/WORKSPACE:
workspace(name = "myproject")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "testrunner-v1",
urls = ["https://github.com/testrunner/v1.zip"],
sha256 = "..."
)
http_archive(
name = "testrunner-v2",
urls = ["https://github.com/testrunner/v2.zip"],
sha256 = "..."
)
local_repository(
name = "A",
path = "../A",
repo_mapping = {"@testrunner" : "@testrunner-v1"}
)
local_repository(
name = "B",
path = "../B",
repo_mapping = {"@testrunner" : "@testrunner-v2"}
)
Cơ chế này cũng có thể dùng để kết nối kim cương. Ví dụ: nếu A
và B
có cùng phần phụ thuộc nhưng gọi phần phụ thuộc đó bằng các tên khác nhau, thì các phần phụ thuộc đó có thể
được tham gia vào myproject/WORKSPACE.
Ghi đè kho lưu trữ từ dòng lệnh
Để ghi đè một kho lưu trữ đã khai báo bằng một kho lưu trữ cục bộ từ dòng lệnh,
hãy sử dụng cờ
--override_repository
. Việc sử dụng cờ này sẽ thay đổi nội dung của các kho lưu trữ bên ngoài mà không thay đổi mã nguồn của bạn.
Ví dụ: để ghi đè @foo
vào thư mục cục bộ /path/to/local/foo
, hãy truyền cờ --override_repository=foo=/path/to/local/foo
.
Một số trường hợp sử dụng bao gồm:
- Khắc phục sự cố. Ví dụ: bạn có thể ghi đè một kho lưu trữ
http_archive
vào một thư mục cục bộ để có thể dễ dàng thay đổi. - Bán hàng. Nếu đang ở trong một môi trường mà bạn không thể thực hiện lệnh gọi mạng, hãy ghi đè các quy tắc lưu trữ dựa trên mạng để trỏ đến các thư mục cục bộ.
Sử dụng proxy
Bazel sẽ chọn địa chỉ proxy từ các biến môi trường HTTPS_PROXY
và HTTP_PROXY
và sử dụng các biến này để tải tệp HTTP/HTTPS xuống (nếu được chỉ định).
Hỗ trợ cho IPv6
Trên các máy chỉ dành cho IPv6, Bazel sẽ có thể tải các phần phụ thuộc xuống mà không cần thay đổi. Tuy nhiên, trên các máy IPv4/IPv6 ngăn xếp kép, Bazel tuân theo quy ước tương tự như Java: nếu IPv4 được bật, IPv4 sẽ được ưu tiên. Trong một số trường hợp, chẳng hạn như khi mạng IPv4 không thể phân giải/truy cập vào các địa chỉ bên ngoài, thì việc này có thể gây ra các ngoại lệ Network unreachable
và lỗi bản dựng.
Trong những trường hợp này, bạn có thể ghi đè hành vi của Bazel để ưu tiên IPv6 hơn bằng cách sử dụng thuộc tính hệ thống java.net.preferIPv6Addresses=true
.
Cụ thể:
Sử dụng tuỳ chọn khởi động
--host_jvm_args=-Djava.net.preferIPv6Addresses=true
, ví dụ: bằng cách thêm dòng sau trong tệp.bazelrc
:startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true
Nếu bạn cũng đang chạy các mục tiêu bản dựng Java cần kết nối với Internet (các kiểm thử tích hợp đôi khi cần kết nối đó), hãy sử dụng
--jvmopt=-Djava.net.preferIPv6Addresses=true
cờ công cụ, chẳng hạn như bằng cách sử dụng dòng sau trong tệp.bazelrc
:build --jvmopt=-Djava.net.preferIPv6Addresses
Nếu bạn đang sử dụng rules_jvm_external, ví dụ: để giải quyết vấn đề về phiên bản của phần phụ thuộc, hãy thêm
-Djava.net.preferIPv6Addresses=true
vào biến môi trườngCOURSIER_OPTS
để cung cấp các tuỳ chọn máy ảo cho Coursier
Phần phụ thuộc bắc cầu
Bazel chỉ đọc các phần phụ thuộc được liệt kê trong tệp WORKSPACE
. Nếu dự án của bạn (A
) phụ thuộc vào một dự án khác (B
) liệt kê phần phụ thuộc trong dự án thứ ba (C
) trong tệp WORKSPACE
của dự án, bạn sẽ phải thêm cả B
và C
vào tệp WORKSPACE
của dự án. Yêu cầu này có thể làm tăng kích thước tệp WORKSPACE
, nhưng hạn chế khả năng một thư viện
có C
ở phiên bản 1.0 và một thư viện khác bao gồm C
ở phiên bản 2.0.
Lưu các phần phụ thuộc bên ngoài vào bộ nhớ đệm
Theo mặc định, Bazel sẽ chỉ tải lại các phần phụ thuộc bên ngoài xuống nếu định nghĩa của các phần phụ thuộc đó thay đổi. Các thay đổi đối với tệp tham chiếu trong định nghĩa (chẳng hạn như bản vá hoặc tệp BUILD
) cũng được xem xét qua bazel.
Để buộc tải xuống lại, hãy sử dụng bazel sync
.
Bố cục
Các phần phụ thuộc bên ngoài đều được tải xuống một thư mục trong thư mục con external
trong cơ sở đầu ra. Trong trường hợp kho lưu trữ cục bộ, một đường liên kết tượng trưng sẽ được tạo tại đó thay vì tạo một thư mục mới.
Bạn có thể xem thư mục external
bằng cách chạy:
ls $(bazel info output_base)/external
Xin lưu ý rằng việc chạy bazel clean
sẽ không thực sự xóa thư mục
bên ngoài. Để xoá tất cả cấu phần phần mềm bên ngoài, hãy sử dụng bazel clean --expunge
.
Bản dựng ngoại tuyến
Đôi khi, bạn mong muốn hoặc cần chạy một bản dựng theo phong cách ngoại tuyến. Đối với các trường hợp sử dụng đơn giản, chẳng hạn như di chuyển trên máy bay, bạn có thể tìm nạp trước các kho lưu trữ cần thiết bằng bazel fetch
hoặc bazel sync
. Hơn nữa, việc sử dụng tuỳ chọn --nofetch
, việc tìm nạp các kho lưu trữ khác có thể bị vô hiệu hoá trong quá trình tạo bản dựng.
Đối với các bản dựng ngoại tuyến thực sự, trong đó việc cung cấp các tệp cần thiết được thực hiện bởi một thực thể khác với bazel, bazel hỗ trợ tuỳ chọn --distdir
. Bất cứ khi nào một quy tắc kho lưu trữ yêu cầu bazel tìm nạp tệp thông qua ctx.download
hoặc ctx.download_and_extract
và cung cấp hàm băm tổng của tệp cần thiết, trước tiên bazel sẽ xem xét các thư mục do tuỳ chọn đó chỉ định cho tệp khớp với tên cơ sở của URL đầu tiên được cung cấp và sử dụng bản sao cục bộ đó nếu giá trị băm khớp.
Bản thân Bazel cũng sử dụng kỹ thuật này để tự khởi động ngoại tuyến từ cấu phần phân phối.
Công cụ này thực hiện việc này bằng cách thu thập tất cả các phần phụ thuộc bên ngoài cần thiết
trong một
distdir_tar
nội bộ.
Tuy nhiên, bazel cho phép thực thi các lệnh tuỳ ý trong quy tắc kho lưu trữ, mà không cần biết liệu chúng có gọi đến mạng hay không. Do đó, bazel không có tuỳ chọn để thực thi các bản dựng hoàn toàn ngoại tuyến. Vì vậy, việc kiểm thử xem một bản dựng có hoạt động đúng cách khi không có mạng hay không cần phải chặn mạng bên ngoài, như bazel cũng cần thực hiện trong kiểm thử khởi động.
Các phương pháp hay nhất
Quy tắc kho lưu trữ
Quy tắc kho lưu trữ thường phải chịu trách nhiệm:
- Phát hiện các chế độ cài đặt hệ thống và ghi vào các tệp.
- Tìm tài nguyên ở nơi khác trên hệ thống.
- Đang tải tài nguyên xuống từ các URL.
- Tạo hoặc liên kết các tệp BUILD vào thư mục kho lưu trữ bên ngoài.
Tránh sử dụng repository_ctx.execute
khi có thể. Ví dụ: khi sử dụng thư viện C++ không phải bằng Bazel có một bản dựng sử dụng Make, bạn nên sử dụng repository_ctx.download()
rồi sau đó viết tệp BUILD tạo bản dựng, thay vì chạy ctx.execute(["make"])
.
Ưu tiên http_archive
hơn git_repository
.
Các lý do là:
- Các quy tắc lưu trữ Git phụ thuộc vào hệ thống
git(1)
, trong khi trình tải HTTP được tích hợp vào Bazel và không có phần phụ thuộc hệ thống. http_archive
hỗ trợ danh sáchurls
dưới dạng phản chiếu vàgit_repository
chỉ hỗ trợremote
.http_archive
hoạt động với bộ nhớ đệm của kho lưu trữ, nhưng không hoạt động vớigit_repository
. Hãy xem #5116 để biết thêm thông tin.
Không sử dụng bind()
. Hãy xem "Cân nhắc việc xoá
liên kết" để biết nội dung thảo luận dài về các vấn đề và giải pháp thay thế.