依赖项

报告问题 查看来源 每晚 · 7.2。 · 7.1敬上 · 7.0 · 6.5 条 · 6.4

如果 A 在构建时需要 B,则目标 A 依赖于目标 B;或 执行时间。“依赖”关系会引发 有向无环图 (DAG),称为依赖关系图

目标的直接依赖项是指路径可以访问的其他目标 长度为 1 的映射关系。目标的传递依赖项包括 通过图表上任意长度的路径所依赖的目标。

事实上,在 build 上下文中,有两个依赖关系图: 实际依赖项和声明的依赖项图。大部分 这两个图表十分相似,无需进行区分, 它对于下面的讨论非常有用。

实际依赖项和声明的依赖项

目标 X 实际上依赖于目标 Y(如果 Y 必须存在); 并保持最新状态,以便正确构建 XBuilt 可能 生成、处理、编译、链接、归档、压缩、执行或 构建期间日常执行的任何其他类型的任务。

目标 X 声明了对目标 Y 的依赖性(如果存在依赖项) X 软件包中从 XY 的边缘。

要实现正确的构建,实际依赖项 A 的图必须是 声明的依赖项的图表 D。也就是说, A 中直接连接的节点 x --> y 也必须直接连接到 D。可以说,D 是 A 的超近似值。

BUILD 文件写入者必须明确声明 依赖项,无需再依赖。

不遵守此原则会导致未定义的行为:构建可能会失败, 但更糟糕的是,构建可能依赖于之前的某些操作, 目标所声明的依赖项Bazel 检查是否存在缺失 并报告错误,但无法将此检查 在所有情况下都很完整

您无需(也不应)尝试列出间接导入的所有内容, 即使 A 在执行时需要它也是如此。

在构建目标 X 期间,构建工具会检查整个传递 关闭 X 的依赖项,以确保这些目标中的所有更改 并会在最终结果中体现出来,并根据需要重新构建中间版本。

依赖项的传递特性导致一种常见的错误。有时 一个文件中的代码可以使用由间接依赖项(即 声明的依赖关系图中的传递边缘,但不是直接边缘。间接 依赖项不会出现在 BUILD 文件中。因为该规则不 直接依赖于提供程序,因此无法跟踪更改, 请参阅以下示例时间轴:

1. 声明的依赖项与实际依赖项匹配

最初,一切正常。软件包 a 中的代码使用软件包 b 中的代码。 软件包 b 中的代码使用 c 软件包中的代码,因此以传递 a 方式 依赖于 c

a/BUILD b/BUILD
rule(
    name = "a",
    srcs = "a.in",
    deps = "//b:b",
)
      
rule(
    name = "b",
    srcs = "b.in",
    deps = "//c:c",
)
      
a / a.in b / b.in
import b;
b.foo();
    
import c;
function foo() {
  c.bar();
}
      
<ph type="x-smartling-placeholder">
</ph> 声明的依赖关系图,其中有连接 a、b 和 c 的箭头
声明的依赖关系图
<ph type="x-smartling-placeholder">
</ph> 与声明的依赖项匹配的实际依赖关系图
                  连接 a、b 和 c 的箭头的图表
实际依赖关系图

声明的依赖项优先于实际依赖项。一切正常。

2. 添加未声明的依赖项

当有人向 a 添加代码以创建 对 c 的直接 actual 依赖项,但忘记在 build 文件中声明它 a/BUILD

a / a.in  
        import b;
        import c;
        b.foo();
        c.garply();
      
 
<ph type="x-smartling-placeholder">
</ph> 声明的依赖关系图,其中有连接 a、b 和 c 的箭头
声明的依赖关系图
<ph type="x-smartling-placeholder">
</ph> 使用箭头连接 a、b 和 c 的实际依赖关系图。一个
                  箭头现在还连通了 A 和 C这与
                  声明的依赖关系图
实际依赖关系图

声明的依赖项不再高估实际依赖项。 这样可能没问题,因为两个图的传递闭包相等, 但掩盖了问题:a 实际对 c 有未声明的依赖项。

3. 声明的依赖关系图与实际依赖关系图之间的偏差

当有人重构 b 以使其不再依赖于它时,就会发现危害 c,无意中将 a 突破了 no 自己的过错。

  b/BUILD
 
rule(
    name = "b",
    srcs = "b.in",
    deps = "//d:d",
)
      
  b / b.in
 
      import d;
      function foo() {
        d.baz();
      }
      
<ph type="x-smartling-placeholder">
</ph> 声明的依赖关系图包含连接 a 和 b 的箭头。
                  b 不再连接到 c,这会断开 a 与 c 的连接
声明的依赖关系图
<ph type="x-smartling-placeholder">
</ph> 显示连接到 b 和 c 的实际依赖关系图,
                  但 b 不再连接到 c
实际依赖关系图

声明的依赖关系图现在是实际 包括以传递方式关闭的依赖项;构建可能会失败

通过确保 已在 BUILD 文件中正确声明第 2 步中引入的 ac

依赖项类型

大多数构建规则都有三个属性,用于指定不同类型的 通用依赖项:srcsdepsdata。具体如下所述。对于 请参见 所有规则共有的属性

许多规则还有适用于特定规则类型的 依赖项,例如 compilerresources。详见 构建百科全书

srcs 个依赖项

输出源文件的规则所直接使用的文件。

deps 个依赖项

指向提供头文件的单独编译的模块的规则; 符号、库、数据等

data 个依赖项

build 目标可能需要一些数据文件才能正常运行。这些数据文件 不是源代码:它们不会影响目标的构建方式。例如, 单元测试可能会将函数的输出与文件的内容进行比较。当您 构建单元测试时,您不需要此文件,但在运行 测试。这同样适用于在执行期间启动的工具。

构建系统在一个隔离的目录中运行测试,该目录下仅列出了 data 可用。因此,如果二进制文件/库/测试需要运行一些文件, 请在 data 中指定这些变量(或包含这些变量的构建规则)。例如:

# I need a config file from a directory named env:
java_binary(
    name = "setenv",
    ...
    data = [":env/default_env.txt"],
)

# I need test data from another directory
sh_test(
    name = "regtest",
    srcs = ["regtest.sh"],
    data = [
        "//data:file1.txt",
        "//data:file2.txt",
        ...
    ],
)

这些文件可通过相对路径 path/to/data/file 获取。在测试中, 可以通过联接测试的源路径来引用这些文件 目录和工作区相对路径,例如 ${TEST_SRCDIR}/workspace/path/to/data/file

使用标签引用目录

查看 BUILD 文件时,您可能会注意到,部分 data 标签 引用的是目录。这些标签以 /./ 结尾,如以下示例所示: 不应使用:

不建议 - data = ["//data/regression:unittest/."]

不建议 - data = ["testdata/."]

不建议 - data = ["testdata/"]

这似乎很方便,尤其是对于测试, 使用目录中的所有数据文件。

但尽量不要这样做。为了确保正确的增量重新编译(以及 重新执行测试)时,构建系统必须了解 作为构建(或测试)输入的完整文件集。如果您指定 则只有在该目录本身存在的情况下, (由于添加或删除文件),但无法检测 可以修改单个文件,因为这些更改不会影响封闭目录。 您应该将目录指定为构建系统的输入,而不是 以显式方式或使用 glob() 函数。(使用 ** 可强制 glob() 为递归。)

建议 - data = glob(["testdata/**"])

遗憾的是,在某些情况下,必须使用目录标签。 例如,如果 testdata 目录包含名称不包含的文件 符合标签语法, 显式枚举文件,或使用 glob() 函数生成的标签无效 错误。在这种情况下,您必须使用目录标签, 出现上述错误重新构建的相关风险。

请注意,如果您必须使用目录标签,则不能引用 具有相对 ../ 路径的父级软件包;而是改用绝对路径 //data/regression:unittest/.

任何需要使用多个文件的外部规则(例如测试)都必须 并明确声明其依赖于所有这些组件。您可以使用 filegroup() 执行以下操作: 在 BUILD 文件中将文件分组:

filegroup(
        name = 'my_data',
        srcs = glob(['my_unittest_data/*'])
)

然后,您可以在测试中引用 my_data 标签作为数据依赖关系。

<ph type="x-smartling-placeholder"></ph> BUILD 文件 <ph type="x-smartling-placeholder"></ph> 曝光度