Bazel 标签是对 BUILD.bazel 文件中定义的源文件和项的字符串引用。其一般格式为:
@<repository_name>//<package_name>:<target_name>
其中:
@<repository_name>//表示已命名的 Bazel 工作区的目录。为方便起见,对于当前工作区(包含当前
BUILD.bazel文件的那个工作区),此命令可简写为//。另请注意,即使在外部代码库中使用,@//也用于指定项目的根工作区。<package_name>是软件包的目录路径,相对于工作区目录。例如,在标签//src:main.cc或//src/lib:foo中,软件包名称分别为src和src/lib。此值可以为空,例如
//:BUILD.bazel指向当前工作区顶级目录中的 build 文件。对于源文件,
<target_name>是相对于其父软件包目录的文件路径,可能包含子目录部分。例如,对于//src:main.cc或//src:extra/extra.cc,目标名称分别为main.cc和extra/extra.cc。对于其他项,
<target_name>对应于BUILD.bazel文件中定义的项(build 制品、build 设置、配置条件等)。按照惯例,其
name属性不应包含目录分隔符,除非在极少数情况下,以避免与来源混淆。对于来自其他 build 系统(例如
GN使用“Targets”“Configs”“Toolchains”和“Pools”来指定不同的事物)的开发者来说,这可能会造成混淆。
还支持使用标签的缩短表达式:
如果标签以代码库名称开头,但不包含冒号,则表示这是一个软件包路径,指向具有相同名称的项。例如,
//src/foo等同于//src/foo:foo。如果标签以冒号开头,则表示相对于当前软件包的名称。例如,
src/foo/BUILD.bazel中显示的“:bar”和“:extra/bar.cc”分别等同于//src/foo:bar和//src/foo:extra/bar.cc。如果标签没有代码库名称且不含英文冒号,则始终是相对于当前软件包的名称,即使它包含目录分隔符也是如此。例如,
src/foo/BUILD.bazel中的“bar/bar.cc”始终是指//src/foo:bar/bar.cc。请注意,这与
//src/foo/bar:bar.cc不同
相对标签和软件包所有权
由于每个源文件只能属于一个软件包,因此相对标签可能无效。例如,在如下所示的项目中:
/home/user/project/
WORKSPACE.bazel
src/
BUILD.bazel
main.cc
extra/
extra.cc
lib/
BUILD.bazel
foo.cc
foo.h
foo.cc 文件属于软件包 src/lib,因此其标签 必须为
//src/lib:foo.cc。
在 src/BUILD.bazel 中使用 src:lib/foo.cc 等标签是错误的:
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"lib/foo.cc", # Error: Label '//src:lib/foo.cc' is invalid because 'src/lib' is a subpackage
"lib/foo.h" # Error: Label '//src:lib/foo.h' is invalid because 'src/lib' is a subpackage
"main.cc",
],
)
从其他软件包访问源文件
默认情况下,给定软件包的源文件无法从其他软件包访问,并且相对软件包标签无效,如下所示:
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"lib:foo.cc", # Error: invalid label 'lib:foo.cc': absolute label must begin with '@' or '//'
"lib:foo.h" # Error: invalid label 'lib:foo.h': absolute label must begin with '@' or '//'
"main.cc",
],
)
即使使用正确的绝对标签,也会发生错误:
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"//src/lib:foo.cc", # Error: no such target '//src/lib:foo.cc': target 'foo.h' not declared in package 'src/lib'
"//src/lib:foo.h" # Error: no such target '//src/lib:foo.h': target 'foo.h' not declared in package 'src/lib'
"main.cc",
],
)
可以通过 export_files() 授予对跨软件包边界的文件进行直接访问的权限:
# From src/lib/BUILD.bazel
export_files([
"foo.cc" ,
"foo.h" ,
])
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"//src/lib:foo.cc", # OK
"//src/lib:foo.h" # OK
"main.cc",
],
)
来自其他软件包的目标访问权限
在 BUILD.bazel 文件中定义的非源文件的带标签项不需要导出,但其 visibility 属性必须允许在自己的软件包之外使用:
# From src/lib/BUILD.bazel
cc_library(
name = " lib" ,
srcs = [ " foo.cc" ],
hdrs = [ " foo.h" ],
visibility = [ " //visibility:public" ], # Anyone can reference this directly!
)
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"main.cc",
],
deps = [ "lib" ], # OK!
)
默认情况下,项仅对同一软件包中的其他项可见。
您可以使用 package() 指令更改软件包中定义的所有项的默认可见性,从而更改此设置:
# From src/lib/BUILD.bazel
# Ensure that all items defined in this file are visible to anyone
package(default_visibility = ["//visibility:public"])
cc_library(
name = " lib" ,
srcs = [ "foo.cc" ],
hdrs = [ "foo.h" ],
)
# From src/BUILD.bazel
cc_binary(
name = "program",
srcs = [
"extra/extra.cc",
"main.cc",
],
deps = [ "lib" ], # OK!
)
有关虚拟软件包的警告
避免在项目中创建具有以下名称的顶级目录:
conditionscommand_line_optionexternalvisibility
因为 Bazel 在 BUILD.bazel 文件中的标签内使用了许多硬编码的“虚拟软件包”。例如:
//visibility:public
//conditions:default
//command_line_option:copt
external 的情况略有不同:它不会出现在 BUILD.bazel 文件中,但会在内部用于管理外部代码库。当用作项目目录时,这会使 Bazel 感到困惑
规范代码库名称
自 Bazel 6.0 起,标签中的代码库名称也可以以 @@ 开头。
启用可选的 BzlMod 功能后,这些标签会用作外部代码库的替代但唯一标签名称,这在项目中使用了复杂的传递依赖项树时非常重要。
例如,@@com_acme_anvil.1.0.3 可能是工作区目录(在项目自己的 BUILD.bazel 文件中由 @anvil 标识,在外部代码库中(例如在 @foo//:BUILD.bazel 内)由 @acme_anvil 标识)的规范名称。这三个标签都将指向同一目录的内容。
规范的代码库名称不会显示在 BUILD.bazel 文件中,但会在分析阶段(执行查看标签值的 Starlark 函数时)或查看 Bazel 查询结果时显示。