Làm việc với các phần phụ thuộc bên ngoài

Báo cáo vấn đề Xem nguồn Hằng đêm · 7,3 · 7.2 · 7.1 · 7 · 6,5

Bazel có thể phụ thuộc vào mục tiêu của các dự án khác. Các phần phụ thuộc từ các thành phần khác các dự án đó được gọi là phần phụ thuộc bên ngoài.

Tệp WORKSPACE (hoặc WORKSPACE.bazel) trong thư mục workspace cho Bazel biết cách lấy các dự án khác nguồn. 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. BUILD tệp 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 chúng từ 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ì lớp này có thể chỉ định rằng một kho lưu trữ có tên Có thể tìm thấy project2 tại /home/user/project2. Sau đó nhắm 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. Hàm này sử dụng cú pháp giống như 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 gọi là quy tắc không gian làm việc). Bazel đi kèm với một vài kho lưu trữ tích hợp sẵn các quy tắc và tập hợp kho lưu trữ Starlark được nhúng . Người dùng cũng có thể ghi kho 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ợ

Bạn có thể sử dụng một số kiểu phần phụ thuộc bên ngoài cơ bản sau:

Tuỳ thuộc vào các dự án khác của Bazel

Nếu muốn sử dụng các mục tiêu 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ộ, hãy tham khảo kho lưu trữ git hoặc tải xuống video (tương ứng).

Ví dụ: giả sử bạn đang làm việc cho một dự án, my-project/ và bạn muốn phụ thuộc vào các mục tiêu trong dự án coworkers-project/ của một đồng nghiệp. Cả hai các dự án này đều sử dụng Bazel, vì vậy, bạn có thể thêm dự án của đồng nghiệp dưới dạng một dự án và sau đó sử dụng bất kỳ mục tiêu nào mà đồng nghiệp của bạn đã tự xác định XÂY DỰNG tệp. 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ó một //foo:bar mục tiêu, thì dự án của bạn có thể gọi mục tiêu đó 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 Bazel

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 cho 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/. Video của đồng nghiệp dự án sẽ 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à 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ó, cho 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 từ BUILD tệp.

Tuỳ thuộc vào các gói bên ngoài

Cấu phần phần mềm và kho lưu trữ Maven

Sử dụng bộ quy tắc rules_jvm_external để tải cấu phần phần mềm xuống qua kho lưu trữ Maven và cung cấp dưới dạng Java phần phụ thuộc.

Đang 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 tập hợp 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. Vì các kho lưu trữ đã tìm nạp được lưu trữ trong cơ sở dữ liệu đầu ra, việc tìm nạp xảy ra trên mỗi không gian làm việc.

Cá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à cuối cùng trong tệp nhị phân cuối cùng. Nhưng đối với trường hợp không đúng, có thể phần phụ thuộc đổ bóng. Hãy xem xét trường hợp sau:

myproject/WORKSPACE

workspace(name = "myproject")

local_repository(
    name = "A",
    path = "../A",
)
local_repository(
    name = "B",
    path = "../B",
)

KHÔNG GIAN LÀM VIỆC

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 AB đều phụ thuộc vào testrunner, nhưng chúng lại phụ thuộc các phiên bản khác nhau của testrunner. Không có lý do gì để những trình chạy kiểm thử này phải không cùng tồn tại một cách yên bình trong myproject, tuy nhiên, chúng sẽ xung đột với nhau khác vì chúng có cùng tên. Để khai báo cả hai phần phụ thuộc, 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 hợp kim cương. Ví dụ: nếu AB có cùng phần phụ thuộc nhưng gọi bằng tên khác, các phần phụ thuộc đó có thể để tham gia 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, sử dụng --override_repository cờ. 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 mình.

Ví dụ: để ghi đè @foo vào thư mục cục bộ /path/to/local/foo, truyền cờ --override_repository=foo=/path/to/local/foo.

Sau đây là một số trường hợp sử dụng:

  • Gỡ lỗi cho vấn đề. Ví dụ: bạn có thể ghi đè kho lưu trữ http_archive vào một thư mục cục bộ nơi bạn có thể thực hiện thay đổi dễ dàng hơn.
  • Nhà cung cấp. Nếu bạn đang ở trong một môi trường không thể thực hiện cuộc gọi mạng, ghi đè các quy tắc về kho lưu trữ dựa trên mạng để trỏ đến các thư mục cục bộ thay thế.

Sử dụng proxy

Bazel sẽ nhận địa chỉ proxy từ HTTPS_PROXYHTTP_PROXY biến môi trường và sử dụng các biến này để tải các tệp HTTP/HTTPS xuống (nếu được chỉ định).

Hỗ trợ cho IPv6

Trên các máy chỉ hỗ trợ IPv6, Bazel sẽ có thể tải các phần phụ thuộc xuống bằng không có thay đổi nào. Tuy nhiên, trên các máy IPv4/IPv6 ngăn xếp kép, Bazel tuân theo cùng một quy ước là Java: nếu IPv4 được bật, IPv4 sẽ được ưu tiên. Trong một số trường hợp, ví dụ: khi mạng IPv4 không thể phân giải/tiếp cận các địa chỉ bên ngoài, điều 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 bằng cách sử dụng thuộc tính hệ thống java.net.preferIPv6Addresses=true. Cụ thể:

  • Sử dụng --host_jvm_args=-Djava.net.preferIPv6Addresses=true tuỳ chọn khởi động, Ví dụ: bằng cách thêm dòng sau vào .bazelrc tệp:

    startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true

  • Nếu bạn đang chạy các mục tiêu bản dựng Java cần kết nối Internet (đôi khi kiểm thử tích hợp cần điều đó), cũng sử dụng --jvmopt=-Djava.net.preferIPv6Addresses=true cờ công cụ, ví dụ: bằng cách đặt 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ụ: để phân giải phiên bản phần phụ thuộc, hãy thêm -Djava.net.preferIPv6Addresses=true đến COURSIER_OPTS biến môi trường để cung cấp các tuỳ chọn JVM 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 trên một phần ba dự án (C) trong tệp WORKSPACE, bạn sẽ phải thêm cả BC vào tệp WORKSPACE của dự án. Yêu cầu này có thể bao quát Kích thước tệp là WORKSPACE, nhưng hạn chế khả năng chỉ có một thư viện bao gồm C ở phiên bản 1.0 và một số 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 các thay đổi về định nghĩa. Các thay đổi đối với tệp được tham chiếu trong định nghĩa (chẳng hạn như bản vá) hoặc BUILD) cũng được bazel xem xét.

Để buộc tải xuống lại, hãy sử dụng bazel sync.

Bố cục

Tất 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 có kho lưu trữ cục bộ, một đường liên kết tượng trưng được tạo vào đó 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

Lưu ý rằng việc chạy bazel clean sẽ không thực sự xoá các thành phần bên ngoài thư mục. Để xoá tất cả cấu phần phần mềm bên ngoài, hãy dùng bazel clean --expunge.

Bản dựng ngoại tuyến

Đôi khi, việc chạy một bản dựng theo cách ngoại tuyến là cần thiết hoặc mong muốn. Để các trường hợp sử dụng đơn giản, chẳng hạn như khi di chuyển trên máy bay, prefetching các URL cần thiết các kho lưu trữ có bazel fetch hoặc bazel sync là đủ; hơn nữa, việc bằng cách sử dụng tuỳ chọn --nofetch, bạn có thể tắt tính năng tìm nạp thêm kho lưu trữ 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ự, cần phải cung cấp các tệp cần thiết 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 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 tổng băm của tệp nếu cần, trước tiên bazel sẽ xem xét các thư mục được chỉ định bởi tuỳ chọn đó để một 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 hàm băm khớp.

Chính Bazel sử dụng kỹ thuật này để tự khởi động ngoại tuyến từ bản phân phối cấu phần phần mềm. Để thực hiện điều này, công cụ này thu thập tất cả dữ liệu bên ngoài cần thiết phần phụ thuộc trong một chiến dịch nội bộ distdir_tar.

Tuy nhiên, bazel cho phép thực thi các lệnh tuỳ ý trong các quy tắc kho lưu trữ, mà không biết liệu chúng có gọi đến mạng hay không. Do đó, bazel không có lựa chọn để thực thi chế độ ngoại tuyến hoàn toàn cho các bản dựng. Vì vậy, việc kiểm thử xem một bản dựng có hoạt động đúng cách hay không khi không có mạng đòi hỏi phải chặn mạng từ bên ngoài, như bazel đã làm trong thử nghiệm Tự thân khởi nghiệp.

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 về:

  • Phát hiện chế độ cài đặt hệ thống và ghi vào tệp.
  • Đang tìm tài nguyên ở nơi khác trong hệ thống.
  • Đang tải tài nguyên xuống từ các URL.
  • Tạo hoặc liên kết tệp BUILD trong 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 C++ không phải Bazel thư viện có bản dựng sử dụng Make, bạn nên dùng repository_ctx.download() sau đó hãy viết tệp BUILD để tạo tệp đó, thay vì chạy ctx.execute(["make"]).

Ưu tiên http_archive đến git_repositorynew_git_repository. Lý do là:

  • Quy tắc kho lưu trữ Git phụ thuộc vào hệ thống git(1) trong khi trình tải xuống HTTP được tạo vào Bazel và không có phần phụ thuộc hệ thống.
  • http_archive hỗ trợ danh sách urls dưới dạng bản sao và git_repository chỉ hỗ trợ một remote.
  • http_archive hoạt động với bộ nhớ đệm của kho lưu trữ, nhưng không git_repository. Xem #5116 để biết thêm thông tin.

Đừng sử dụng bind(). Hãy xem phần "Cân nhắc xóa ràng buộc" trong một khoảng thời gian dài thảo luận về các vấn đề và phương án thay thế.