使用外部依赖项

<ph type="x-smartling-placeholder"></ph> 报告问题 查看来源 敬上 每晚 · 7.3。 · 7.2 条 · 7.1。 · 7.0。 · 6.5

Bazel 可以依赖于其他项目中的目标。其他来源的依赖项 项目称为“外部依赖项”。

WORKSPACE 文件(或 WORKSPACE.bazel 文件) 工作区目录 告诉 Bazel 如何获取其他项目的来源。这些其他项目可以 包含一个或多个 BUILD 文件,这些文件具有自己的目标。BUILD 个文件 主项目可以使用这些外部目标的名称 WORKSPACE 文件。

例如,假设系统中有两个项目:

/
  home/
    user/
      project1/
        WORKSPACE
        BUILD
        srcs/
          ...
      project2/
        WORKSPACE
        BUILD
        my-libs/

如果 project1 想要依赖于 :foo 中定义的目标 /home/user/project2/BUILD 时,它可以指定名为 可以在 /home/user/project2 找到 project2。然后定位 /home/user/project1/BUILD 可能依赖于 @project2//:foo

WORKSPACE 文件允许用户依赖于 或从互联网下载的它使用的语法与 BUILD 相同 但允许使用一组名为仓库规则(有时 (也称为“工作区规则”)。Bazel 附带有几个内置代码库 规则和一组嵌入式 Starlark 代码库 规则。用户还可以编写自定义代码库 规则来实现更复杂的行为。

支持的外部依赖项类型

您可以使用一些基本类型的外部依赖项:

依赖于其他 Bazel 项目

如果要使用另一个 Bazel 项目中的目标,您可以 使用 local_repositorygit_repositoryhttp_archive 从本地文件系统对其添加符号链接、引用 Git 代码库或下载 。

例如,假设您正在处理一个项目 my-project/,并希望 依赖于同事项目 coworkers-project/ 中的目标。两者都有 项目使用 Bazel,因此您可以将同事的项目添加为外部 依赖项,然后使用同事自行定义的任何目标 BUILD 文件。您需要将以下内容添加到 my_project/WORKSPACE 中:

local_repository(
    name = "coworkers_project",
    path = "/path/to/coworkers-project",
)

如果您同事的目标 //foo:bar,则您的项目可以将其引用为 @coworkers_project//foo:bar。外部项目名称必须 有效的工作区名称

依赖于非 Bazel 项目

new_ 为前缀的规则,例如 new_local_repository, 允许您基于不使用 Bazel 的项目创建目标。

例如,假设您正在处理一个项目 my-project/,并希望 依赖于您同事的项目 coworkers-project/。您同事的 项目使用 make 进行构建,但您希望使用某个 .so 文件 生成的内容。为此,请将以下内容添加到 my_project/WORKSPACE 中:

new_local_repository(
    name = "coworkers_project",
    path = "/path/to/coworkers-project",
    build_file = "coworker.BUILD",
)

build_file 用于指定要叠加到现有项目的 BUILD 文件, 示例:

cc_library(
    name = "some-lib",
    srcs = glob(["**"]),
    visibility = ["//visibility:public"],
)

然后,您就可以依赖于项目中的 @coworkers_project//:some-lib BUILD 个文件。

取决于外部软件包

Maven 制品和代码库

使用规则集 rules_jvm_external 从 Maven 代码库下载制品,并以 Java 形式提供它们 依赖项

提取依赖项

默认情况下,在 bazel build 期间,系统会根据需要提取外部依赖项。如果 如果您想预提取一组特定目标所需的依赖项,请使用 bazel fetch。 如需无条件提取所有外部依赖项,请使用 bazel sync。 由于提取的代码库存储在输出库中,因此 按工作区统计。

覆盖依赖项

我们建议您尽可能在一个版本政策中 项目。这对于您在编译时所针对并最终生成的依赖项而言是必需的 放在最终二进制文件中但如果情况并非如此,则您可以 影子依赖项。请考虑以下场景:

myproject/WORKSPACE

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(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 = "..."
)

AB 依赖项均依赖于 testrunner,但也依赖于它们 testrunner 的不同版本。这些测试运行程序没有理由 未在myproject内和平共存,但会与每个 其他,因为它们的名称相同。要声明这两个依赖项, 更新 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"}
)

此机制也可用于连接菱形。例如,如果 AB 具有相同的依赖项,但以不同的名称对其进行调用,那么这些依赖项可以 添加到 myproject/WORKSPACE 中

从命令行替换代码库

如需从命令行使用本地代码库替换已声明的代码库,请执行以下操作: 使用 --override_repository 标志。使用此标志会更改外部代码库的内容 更改源代码

例如,如需将 @foo 替换成本地目录 /path/to/local/foo,请使用以下代码: 传递 --override_repository=foo=/path/to/local/foo 标志。

部分用例包括:

  • 调试问题。例如,您可以替换 http_archive 代码库 本地目录,以便您更轻松地进行更改
  • 供应商开发。如果您处于无法进行网络调用的环境中, 覆盖基于网络的代码库规则以指向本地目录 。

使用代理

Bazel 将从 HTTPS_PROXYHTTP_PROXY 中选择代理地址 环境变量,并使用这些变量下载 HTTP/HTTPS 文件(如果已指定)。

支持 IPv6

在仅支持 IPv6 的机器上,Bazel 将能够使用 没有变化。但在双栈 IPv4/IPv6 机器上,Bazel 遵循 Java 惯例:如果启用了 IPv4,则首选 IPv4。在某些情况下 例如当 IPv4 网络无法解析/访问外部地址时, 这可能会导致 Network unreachable 异常和构建失败。 在这些情况下,您可以替换 Bazel 的行为来首选 IPv6 通过使用 java.net.preferIPv6Addresses=true 系统属性来实现。 具体而言:

  • 使用--host_jvm_args=-Djava.net.preferIPv6Addresses=true 启动选项、 例如,将以下代码行添加到 .bazelrc 文件

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

  • 如果您运行的 Java 构建目标需要连接到互联网 (集成测试有时需要这样做),也可使用 --jvmopt=-Djava.net.preferIPv6Addresses=true 工具标志,例如使用 .bazelrc 文件中的下面这行代码:

    build --jvmopt=-Djava.net.preferIPv6Addresses

  • 如果您使用的是 rules_jvm_external, 例如,对于依赖项版本解析,还要添加 -Djava.net.preferIPv6Addresses=true后到达COURSIER_OPTS 环境变量,用于为 Coursier 提供 JVM 选项

传递依赖项

Bazel 只会读取 WORKSPACE 文件中列出的依赖项。如果您的项目 (A) 依赖于另一个项目 (B),而该项目列出了对第三个项目的依赖项 项目 (C) 中,则必须在 WORKSPACE 文件中同时添加BC 添加到项目的 WORKSPACE 文件中。此要求可将 WORKSPACE 文件大小,但会限制只有一个库的可能性 在 1.0 版中包含 C,另一个在 2.0 版中包含 C

缓存外部依赖项

默认情况下,只有在以下情况下,Bazel 才会重新下载外部依赖项: 定义更改。对定义中引用的文件(如补丁)进行了更改 或 BUILD 文件)。

如需强制重新下载,请使用 bazel sync

布局

外部依赖项会全部下载到子目录下的某个目录中 输出库中的 external。如果 本地代码库,则系统会创建一个符号链接 而不必创建新目录 您可以通过运行以下命令来查看 external 目录:

ls $(bazel info output_base)/external

请注意,运行 bazel clean 并不会实际删除 目录。如需移除所有外部工件,请使用 bazel clean --expunge

离线构建

有时需要或需要离线运行构建。对于 例如在飞机上旅行 prefetching所需的 使用 bazel fetchbazel sync 的代码库就足够了;此外, 使用 --nofetch 选项,可以停用提取更多代码库的功能 构建容器。

对于需要完成所需文件的离线构建 bazel 以外的实体,bazel 支持 --distdir。每当代码库规则要求 bazel 通过 ctx.downloadctx.download_and_extract 并提供文件的哈希值总和 bazel 将首先查看该选项指定的目录, 与提供的首个网址的基名匹配的文件,然后使用该本地副本 如果哈希值匹配。

Bazel 本身使用此技术从发行版 工件。 为此,它会收集所有必要的外部 依赖项 一个内部 IP 地址 distdir_tar

但是,bazel 允许在仓库规则中执行任意命令, 而不知道自己是否会向广告联盟发出调用请求因此,bazel 没有 强制构建完全离线测试构建能否正常运行 需要对网络进行外部屏蔽,就像 bazel 在其 引导测试

最佳做法

仓库规则

仓库规则通常应负责:

  • 检测系统设置并将其写入文件。
  • 查找系统其他位置的资源。
  • 从网址下载资源。
  • 生成 BUILD 文件或通过符号链接将其指向外部代码库目录。

尽可能避免使用 repository_ctx.execute。例如,使用非 Bazel C++ 包含使用 Make 的 build 的库,最好使用 repository_ctx.download(),然后使用 编写一个 BUILD 文件来构建它,而不是运行 ctx.execute(["make"])

http_archive 设置为 git_repositorynew_git_repository。原因如下:

  • Git 代码库规则依赖于系统 git(1),而 HTTP 下载程序是构建的 并且没有系统依赖项
  • http_archive 支持 urls 列表作为镜像,git_repository 仅支持 单个 remote
  • http_archive 可与代码库缓存结合使用,但不适用于 git_repository。请参阅 #5116 了解详情。

请勿使用 bind()。有关详情,请参阅考虑删除 绑定”长时间 讨论其问题和替代方案。