所有目标都只能归属于一个软件包。目标的名称称为其标签。每个标签唯一地标识一个目标。规范化形式的典型标签如下所示:
@myrepo//my/app/main:app_binary
标签的第一部分是代码库名称 @myrepo//
。在典型情况下,如果标签引用的是其所用代码库,则代码库标识符可以缩写为 //
。因此,在 @myrepo
中,此标签通常写为
//my/app/main:app_binary
标签的第二部分是未限定的软件包名称 my/app/main
,即相对于代码库根目录的软件包路径。代码库名称和非限定软件包名称共同构成完全限定软件包名称 @myrepo//my/app/main
。如果标签所指代与其使用的软件包相同,则可以省略软件包名称(还可选择省略冒号)。因此,在 @myrepo//my/app/main
中,此标签可以按以下方式之一写入:
app_binary
:app_binary
通常,对于文件,我们会省略英文冒号,但对于规则,则会保留英文冒号,但这并不重要。
冒号后面的标签部分 app_binary
是非限定的目标名称。如果它与软件包路径的最后一个组件匹配,则可以省略它和英文冒号。因此,以下两个标签是等效的:
//my/app/lib
//my/app/lib:lib
软件包的子目录中文件目标的名称是该文件相对于软件包根目录(包含 BUILD
文件的目录)的路径。因此,此文件位于代码库的 my/app/main/testdata
子目录中:
//my/app/main:testdata/input.txt
//my/app
和 @some_repo//my/app
等字符串有两个含义,具体取决于使用它们的上下文:当 Bazel 需要标签时,它们分别表示 //my/app:app
和 @some_repo//my/app:app
。但是,当 Bazel 需要软件包时(例如在 package_group
规范中),它们会引用包含该标签的软件包。
BUILD
文件中的一个常见错误是使用 //my/app
引用软件包或引用软件包中的所有目标,但实际上并没有这样做。请注意,它相当于 //my/app:app
,因此它会在当前代码库的 my/app
软件包中命名 app
目标。
不过,在 package_group
的规范或 .bzl
文件中,建议使用 //my/app
来引用软件包,因为这可以清楚地表明软件包名称是绝对的,并且位于工作区的顶级目录中。
相对标签不能用于引用其他软件包中的目标;在这种情况下,必须始终指定代码库标识符和软件包名称。例如,如果源代码树同时包含软件包 my/app
和软件包 my/app/testdata
(这两个目录各有自己的 BUILD
文件),则后者软件包包含一个名为 testdepot.zip
的文件。您可以通过以下两种方式(一种错误,一种正确)在 //my/app:BUILD
中引用此文件:
错误 - testdata
是另一个软件包,因此您无法使用相对路径
testdata/testdepot.zip
正确 - 使用完整路径引用 testdata
//my/app/testdata:testdepot.zip
以 @//
开头的标签是对主代码库的引用,即使从外部代码库引用,也仍然有效。因此,从外部代码库引用时,@//a/b/c
与 //a/b/c
不同。前者指回主代码库,而后者会在外部代码库本身中查找 //a/b/c
。在主代码库中编写引用主代码库中目标的规则时,这一点尤为重要,并且将通过外部代码库使用。
如需了解引用目标的不同方法,请参阅目标模式。
标签的词法规范
标签语法不鼓励使用对 shell 具有特殊含义的元字符。这有助于避免无意中引号问题,并更轻松地构建用于操作标签的工具和脚本,例如 Bazel 查询语言。
下面列出了允许的目标名称的确切详细信息。
目标名称 - package-name:target-name
target-name
是软件包中的目标名称。规则的名称是 BUILD
文件中规则声明中的 name
属性的值;文件的名称是相对于包含 BUILD
文件的目录的路径名。
目标名称必须完全由 a
-z
、A
-Z
、0
-9
集合中的字符以及标点符号 !%-@^_"#$&'()*-+,;<=>?[]{|}~/.
组成。
文件名必须是正常形式的相对路径名,这意味着它们不得以正斜杠开头或结尾(例如,/foo
和 foo/
均不允许),也不得包含多个连续的正斜杠作为路径分隔符(例如 foo//bar
)。同样,上级引用 (..
) 和当前目录引用 (./
) 也不允许。
错误 - 请勿使用 `..` 来引用其他软件包中的文件
正确 - 使用“//package-name:filename”
虽然在文件目标的名称中使用 /
很常见,但请避免在规则的名称中使用 /
。尤其是在使用标签的简写形式时,可能会让读者感到困惑。标签 //foo/bar/wiz
始终是 //foo/bar/wiz:wiz
的简写形式,即使没有此类软件包 foo/bar/wiz
;它绝不会引用 //foo:bar/wiz
,即使该目标存在也是如此。
不过,在某些情况下,使用斜线会很方便,有时甚至是必要的。例如,某些规则的名称必须与其主要源文件(可能位于软件包的子目录中)相匹配。
软件包名称 - //package-name:target-name
软件包的名称是包含其 BUILD
文件的目录的名称,相对于包含的代码库的顶级目录。例如:my/app
。
软件包名称必须完全由 A
-Z
、a
-z
、0
-9
、'/
'、'-
'、'.
'、'@
' 和 '_
' 集合中的字符组成,并且不能以斜线开头。
对于目录结构对其模块系统具有重要意义的语言(例如 Java),请务必选择在该语言中有效的标识符目录名称。
虽然 Bazel 支持工作区的根软件包(例如 //:foo
)中的目标,但最好将该软件包留空,以便所有有意义的软件包都有描述性名称。
软件包名称不得包含子字符串 //
,也不得以正斜线结尾。
规则
规则用于指定输入和输出之间的关系,以及构建输出的步骤。规则可以属于多种不同种类(有时称为“规则类”),它们会生成已编译的可执行文件和库、测试可执行文件以及其他受支持的输出,如构建百科全书中所述。
BUILD
文件通过调用规则来声明目标。
在下面的示例中,我们会看到使用 cc_binary
规则声明目标 my_app
。
cc_binary(
name = "my_app",
srcs = ["my_app.cc"],
deps = [
"//absl/base",
"//absl/strings",
],
)
每个规则调用都有一个 name
属性(必须是有效的目标名称),用于在 BUILD
文件的软件包中声明目标。
每条规则都有一组属性;给定规则适用的属性以及每个属性的重要性和语义取决于规则的类型;如需查看规则及其对应属性的列表,请参阅build 百科全书。每个属性都有一个名称和一个类型。属性可以具有的常见类型包括整数、标签、标签列表、字符串、字符串列表、输出标签、输出标签列表。并非所有属性都需要在每条规则中指定。因此,属性会形成一个字典,其中键(名称)对应于可选的类型化值。
许多规则中都存在 srcs
属性,其类型为“标签列表”;其值(如果有)是标签列表,其中每个标签都是此规则的输入目标的名称。
在某些情况下,规则类型的名称有点任意性,更有趣的是规则生成的文件的名称,genrule 就是如此。如需了解详情,请参阅常规规则:genrule。
在其他情况下,名称很重要:例如,对于 *_binary
和 *_test
规则,规则名称决定了 build 生成的可执行文件的名称。
针对目标的这种有向无环图称为“目标图”或“构建依赖关系图”,是 Bazel 查询工具在哪个网域上运行。
目标 | BUILD 文件 |