最佳实践

报告问题 查看源代码 每夜版 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

本页面假定您熟悉 Bazel,并提供有关如何构建项目以充分利用 Bazel 功能的指南和建议。

总体目标是:

  • 使用精细的依赖项来实现并行性和增量性。
  • 保持依赖项的良好封装。
  • 使代码结构合理且可测试。
  • 创建易于理解和维护的 build 配置。

这些指南并非要求:很少有项目能够完全遵守这些指南。正如 lint 的 man 页面所说,“如果有人能编写出在严格检查下不产生任何错误的真实程序,我们将给予特别奖励。”不过,尽可能多地采用这些原则应该能让项目更易读、更不易出错,并能更快地构建。

本页面使用了此 RFC 中所述的要求级别。

运行 build 和测试

项目应始终能够在稳定分支上成功运行 bazel build //...bazel test //...。必要但在某些情况下(例如,需要特定的 build 标志、无法在特定平台上 build、需要许可协议)无法 build 的目标应尽可能具体地标记(例如,“requires-osx”)。与“manual”标记相比,这种标记方式可以更精细地过滤目标,并让检查 BUILD 文件的人员了解目标的限制。

第三方依赖项

您可以声明第三方依赖项:

  • 或者在 MODULE.bazel 文件中将它们声明为远程代码库。
  • 或者将它们放在工作区目录下的 third_party/ 目录中。

取决于二进制文件

应尽可能从源代码构建所有内容。一般来说,这意味着您需要创建 BUILD 文件并从其来源构建 some-library.so,然后依赖于该目标,而不是依赖于库 some-library.so

始终从源代码进行构建可确保构建不会使用以不兼容的标志或不同的架构构建的库。还有一些功能(例如覆盖率、静态分析或动态分析)只能在源代码上运行。

版本控制

尽可能从 Head 构建所有代码。如果必须使用版本,请避免在目标名称中包含版本(例如,使用 //guava,而不是 //guava-20.0)。这种命名方式可让库更易于更新(只需更新一个目标)。它还能更好地应对菱形依赖项问题:如果一个库依赖于 guava-19.0,而另一个库依赖于 guava-20.0,您最终可能会得到一个尝试依赖于两个不同版本的库。如果您创建了一个误导性别名,将两个目标都指向一个 guava 库,那么 BUILD 文件就是误导性的。

使用 .bazelrc 文件

对于特定于项目的选项,请使用 workspace/.bazelrc 的配置文件(请参阅 bazelrc 格式)。

如果您想为项目提供您想签入源代码控制系统的用户专用选项,请添加以下行:

try-import %workspace%/user.bazelrc

(或任何其他文件名),然后在 workspace/.bazelrc 中添加 user.bazelrc.gitignore

开源 bazelrc-preset.bzl{: .external} 会生成与您的 Bazel 版本相匹配的自定义 bazelrc 文件,并提供一组预设的推荐标志。

软件包

包含可构建文件的每个目录都应是一个软件包。如果 BUILD 文件引用了子目录中的文件(例如 srcs = ["a/b/C.java"]),则表明应向该子目录添加 BUILD 文件。这种结构存在的时间越长,就越有可能无意中创建循环依赖项,目标的范围会逐渐扩大,并且必须更新的反向依赖项数量也会越来越多。