BUILD
文件格式遵循与 Go 相同的方法,后者通过标准化工具处理大多数格式问题。Buildifier 工具用于以标准样式解析和发出源代码。因此,每个 BUILD
文件的格式均以相同的自动方式设置,因此在代码审核期间不会遇到格式问题。它还使工具能够更轻松地理解、修改和生成 BUILD
文件。
BUILD
文件格式必须与 buildifier
的输出结果一致。
格式设置示例
# Test code implementing the Foo controller.
package(default_testonly = True)
py_test(
name = "foo_test",
srcs = glob(["*.py"]),
data = [
"//data/production/foo:startfoo",
"//foo",
"//third_party/java/jdk:jdk-k8",
],
flaky = True,
deps = [
":check_bar_lib",
":foo_data_check",
":pick_foo_port",
"//pyglib",
"//testing/pybase",
],
)
文件结构
建议:请按以下顺序(每个元素都是可选的):
软件包说明(注释)
全部
load()
个对账单package()
函数。对规则和宏的调用
构建器可以区分独立注释和附加到元素的注释。如果注释未附加到特定元素,请在其后面添加一个空行。在执行自动更改(例如,在删除规则时保留或移除评论)时,区分评论非常重要。
# Standalone comment (such as to make a section in a file)
# Comment for the cc_library below
cc_library(name = "cc")
对当前软件包中目标的引用
文件应通过相对于软件包目录的路径进行引用(从未使用向上引用,例如 ..
)。生成的文件应带有“:
”前缀,以表示它们不是源文件。源文件不应添加前缀 :
。规则应带有前缀 :
。例如,假设 x.cc
是一个源文件:
cc_library(
name = "lib",
srcs = ["x.cc"],
hdrs = [":gen_header"],
)
genrule(
name = "gen_header",
srcs = [],
outs = ["x.h"],
cmd = "echo 'int x();' > $@",
)
目标命名
目标名称应为描述性名称。如果目标包含一个源文件,则目标通常应该具有源自该来源的名称(例如,chat.cc
的 cc_library
可以命名为 chat
,DirectMessage.java
的 java_library
可以命名为 direct_message
)。
软件包的同名目标(目标与包含目录同名的目标)应提供目录名称所描述的功能。如果没有此类目标,请勿创建同名目标。
在引用同名目标时,首选使用简称(//x
而不是 //x:x
)。如果您在同一个软件包中,请优先使用本地引用(:x
而不是 //x
)。
避免使用具有特殊含义的“预留”目标名称。这包括 all
、__pkg__
和 __subpackages__
,这些名称具有特殊语义,在使用时可能会导致混淆和意外行为。
在没有普遍适用的团队惯例的情况下,以下是在 Google 广泛采用的一些不具有约束力的建议:
- 一般情况下,请使用 "snake_case"
- 对于具有一个
src
的java_library
,这意味着使用的名称与不带扩展名的文件名不同 - 对于 Java
*_binary
和*_test
规则,请使用“大驼峰式大小写”。这样一来,目标名称就可以与其中一个src
匹配。对于java_test
,这样就可以根据目标名称推断test_class
属性。
- 对于具有一个
- 如果特定目标有多个变体,请添加后缀以消除歧义(例如,
:foo_dev
、:foo_prod
或:bar_x86
、:bar_x64
) - 为
_test
目标添加_test
、_unittest
、Test
或Tests
后缀 - 避免使用
_lib
或_library
等无意义的后缀(除非有必要,以免_library
目标与其对应的_binary
之间发生冲突) - 对于 proto 相关目标:
proto_library
目标的名称应以_proto
结尾- 特定于语言的
*_proto_library
规则应与底层 proto 匹配,但将_proto
替换为语言特有的后缀,例如:cc_proto_library
:_cc_proto
java_proto_library
:_java_proto
java_lite_proto_library
:_java_proto_lite
公开范围
应尽可能缩小可见性的范围,同时仍允许通过测试和反向依赖项进行访问。请根据需要使用 __pkg__
和 __subpackages__
。
避免将软件包 default_visibility
设置为 //visibility:public
。
应仅针对项目的公共 API 中的目标单独设置 //visibility:public
。这些库可以是设计为外部项目所依赖的库,也可以是可供外部项目的构建流程使用的二进制文件。
依赖项
依赖项应仅限于直接依赖项(规则中列出的来源所需的依赖项)。不列出传递依赖项。
应首先列出软件包本地依赖项,并以与上文对当前软件包中的目标的引用部分兼容的引用方式(而不是通过其绝对软件包名称)引用这些依赖项。
倾向于直接将依赖项作为单个列表列出。将多个目标的“常见”依赖项放入变量会降低可维护性,使工具无法更改目标的依赖项,并可能导致未使用的依赖项。
Glob
使用 []
表示“无目标”。请勿使用与任何内容都不匹配的 glob,因为它比空列表更容易出错,也不太明显。
递归
请勿使用递归 glob 匹配源文件(例如 glob(["**/*.java"])
)。
递归 glob 会使 BUILD
文件难以推断,因为它们会跳过包含 BUILD
文件的子目录。
递归 glob 通常比为每个目录定义一个依赖关系图的 BUILD
文件效率低下,因为这样可以实现更好的远程缓存和并行性。
最好在每个目录中编写一个 BUILD
文件,并在它们之间定义依赖关系图。
非递归
非递归 glob 通常可以接受。
其他惯例
使用大写和下划线声明常量(例如
GLOBAL_CONSTANT
),使用小写和下划线声明变量(例如my_variable
)。请勿拆分标签,即使标签超过 79 个字符也不例外。标签尽可能应为字符串字面量。说明:便于查找和替换。也有助于提高可读性。
name 属性的值应为字面量常量字符串(宏中除外)。说明:外部工具使用 name 属性来引用规则。他们需要在无需解读代码的情况下找出规则。
设置布尔值类型的属性时,请使用布尔值,而不是整数值。由于旧版原因,规则仍会根据需要将整数转换为布尔值,但不建议这样做。理由:
flaky = 1
可能会误读为“通过重新运行一次来移除此目标”。flaky = True
明确表示“此测试不稳定”。
与 Python 样式的差异指南
虽然我们的目标是实现与 Python 样式指南兼容,但两者之间还是存在一些差异:
没有严格的行长度限制。长评论和长字符串通常会拆分为 79 列,但这不是必需的。不应在代码审核或提交前脚本中强制执行该机制。说明:标签可以很长并且超过此限制。
BUILD
文件通常由工具生成或修改,但不适用于行长度限制。不支持隐式字符串串联。使用
+
运算符。 说明:BUILD
文件包含许多字符串列表。我们很容易忘记英文逗号,这会导致完全不同的结果。这在过去导致了许多 bug。另请参阅此讨论。在规则中的关键字参数的
=
符号周围使用空格。说明:具名参数比 Python 中更频繁,并且始终在单独的一行上。聊天室可提高可读性。这种惯例已经存在很长时间,不值得修改所有现有的BUILD
文件。默认情况下,对字符串使用双引号。说明:虽然 Python 样式指南中并未指明这一点,但建议保证一致性。因此,我们决定仅使用带英文双引号的字符串。许多语言都为字符串字面量使用双引号。
在两个顶级定义之间使用一个空行。说明:
BUILD
文件的结构与典型的 Python 文件不同。它只有顶级语句。使用单个空行会缩短BUILD
文件。