Bazel 规范中的`load` 顺序还是仅仅因为实现?

ymo*_*poo 2 bazel bazel-rules

我在用 Bazel 构建 Go 项目时遇到了一个问题,发现它的根本原因是load导入的顺序@io_bazel_rules_go

收到答案后,我参考了 Bazel 的官方文档,如果它是在规范中定义的,或者只是对实现的隐式依赖。我还不能检查所有官方文档,但听起来以下文档与此问题相关,但仍然不清楚load影响构建的顺序;在我经历的情况下,似乎较早的声明胜过后来的声明。

任何人都可以澄清这是否是规范?

Jay*_*rod 5

关于覆盖外部存储库的文档含糊不清,但https://docs.bazel.build/versions/2.2.0/external.html可能是最好的参考。

我的理解是:

  • WORKSPACE在被调用的函数中声明的存储库WORKSPACE是惰性求值的。这很重要,因为评估存储库规则可能非常昂贵(它们往往会下载大文件),并且可能不需要很多构建。
  • 多次声明同名存储库并不是错误。如果尚未评估存储库规则,则将使用最后一个声明。
  • 当存储库中的任何标签被解析时,将评估存储库规则。这包括:
    • .bzl使用load语句加载文件。
    • 将属性中的标签传递给另一个被评估的存储库规则。
    • ctx.path在评估的另一个存储库规则中的标签上使用。
    • (在WORKSPACE完全解决之后)构建一个加载某些内容或依赖于存储库中某些内容的目标。
  • 评估存储库规则后,将无法再覆盖它。稍后声明的同名存储库将被静默忽略。

这种逻辑令人困惑,当多次声明规则时,很难理解使用的是什么版本。

  • 理想情况下,每个规则都应该声明一次,WORKSPACE以尽量减少混淆。当然,如果您的依赖项提供声明传递依赖项的函数,这可能会很困难。在某些情况下,您可能最终会手动内联这些函数。
  • 像这样的依赖函数go_rules_dependencies应该避免覆盖使用这样的_maybe函数声明的任何东西:
def _maybe(repo_rule, name, **kwargs):
    if name not in native.existing_rules():
        repo_rule(name = name, **kwargs)
Run Code Online (Sandbox Code Playgroud)
  • 安排您的WORKSPACE文件以确保直接依赖项已声明并可能更早解决。这可能会使对相关声明进行分组变得更加困难,但评估语义会更加清晰。
    • http_archive以及git_repository规则集和直接依赖项的存储库。
    • load 存储库规则和依赖函数的语句。
    • 其他直接依赖(例如,go_repository)。
    • 为传递依赖调用依赖函数。
    • 工具链注册。

对于调试,该native.existing_rules功能非常方便。它返回到目前为止声明的所有存储库的列表,以及它们声明的属性。定义一个调用它并打印结果的函数,然后从WORKSPACE.

  • 感谢您如此详细而简洁的回答!您的回答对我理解这种行为有很大帮助。 (2认同)