精讲:掌握 `//path/to/package:target-name` 语法,精准引用构建目标)
Bazel 标签Label精讲掌握//path/to/package:target-name语法精准引用构建目标【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel在 Bazel 的世界里//main:hello-world、//lib:hello-time这样的字符串随处可见——无论是写在BUILD文件里还是敲在命令行上。它们是 Bazel 定位构建目标的“地址”官方称之为标签Label。本文以 Bazel 官方 C 教程中的《Use labels to reference targets》为基础系统讲解标签的完整语法、规则目标与文件目标的差异、仓库根目录与同包引用等快捷写法并结合本仓库的examples示例与docs/concepts/labels.mdx概念文档进行源码级印证。读完本文你将能正确书写、解读并排错任何出现在BUILD文件或命令行中的 Bazel 标签。标签语法三段式结构标签的通用语法为//path/to/package:target-name以两个连续斜杠//开头中间以冒号:分隔整体由三部分构成//工作区根目录标识符表示“从这个仓库的根目录开始寻址”path/to/package包路径即从工作区根目录到包含BUILD文件的目录之间的相对路径target-name目标名称即BUILD文件中规则的name属性值规则目标或文件相对于包根目录的路径文件目标。例如//main:hello-world含义是“位于工作区根目录下main包该目录含BUILD文件中的、名为hello-world的目标”。工作区根的判断标准标签中的path/to/package是相对工作区根目录计算的。在启用 Bzlmod 的现代 Bazel 项目中工作区根目录就是存放MODULE.bazel文件的目录在旧式工作区中则是存放WORKSPACE文件的目录。这一点在新旧版本文档中都有明确记载当前 docs/tutorials/cpp-labels.mdx 写的是MODULE.bazel而 docs/versions/7.6.1/tutorials/cpp-labels.mdx 等旧版文档仍以WORKSPACE文件为准两处表述差异恰好反映了 Bazel 从 WORKSPACE 迁移到 MODULE.bazel 的历史演进。规则目标与文件目标target-name的两种含义标签的冒号后部分target-name指代什么取决于目标类型规则目标Rule Target如果目标是规则目标即BUILD文件中调用某个规则声明出来的目标那么path/to/package是从工作区根到包含BUILD文件的目录的路径target-name就是你在BUILD文件中为规则指定的name属性值。以本仓库 examples/cpp/BUILD 为例cc_library( name hello-lib, srcs [hello-lib.cc], hdrs [hello-lib.h], ) cc_binary( name hello-world, srcs [hello-world.cc], deps [:hello-lib], )这里cc_library规则实例化出的目标hello-lib其标签为//examples/cpp:hello-libcc_binary目标hello-world的标签为//examples/cpp:hello-world。注意deps [:hello-lib]使用的是同包简写形式见下文“同包引用”一节。文件目标File Target如果目标是文件目标仓库中的源文件或由规则生成的文件那么path/to/package是包根目录即包含该包BUILD文件的目录的路径target-name是该文件的名称包含它相对于包根目录的完整路径。例如 docs/concepts/labels.mdx 中的例子位于my/app/main/testdata子目录下的文件input.txt其标签写作//my/app/main:testdata/input.txt包路径是my/app/main而目标名部分是testdata/input.txt——冒号后的部分完整保留了文件在包内的相对路径这正是文件目标与规则目标的显著差异。本仓库中也有真实案例examples/cpp/BUILD 里的runfile目标通过data [//examples:runfile.txt]引用了一个文件目标cc_binary( name runfile, srcs [runfile.cc], copts [-stdc17], data [//examples:runfile.txt], deps [rules_cc//cc/runfiles], )//examples:runfile.txt指的就是工作区根下examples包中的文件runfile.txt。它之所以能被examples/cpp包中的目标引用是因为 examples/BUILD 中声明了package(default_visibility [//visibility:public])并执行了exports_files([runfile.txt])——这印证了文件目标的可见性同样受visibility规则约束。快捷写法一仓库根目录//:target-name当目标位于仓库根目录的包即根包根目录本身包含BUILD文件时包路径为空直接写成//:target-name本仓库根目录的 BUILD 文件即为根包的BUILD文件其中的目标都可以用//:xxx形式引用。//:target-name与//根包:target-name是等价的。快捷写法二同包引用:target-name当你在同一个BUILD文件内部引用目标时连//工作区根标识符都可以省略直接写:target-name最典型的例子就是 examples/cpp/BUILD 中的deps [:hello-lib]——hello-world和hello-lib同处examples/cpp包因此无需写全//examples/cpp:hello-lib。官方 docs/start/cpp.mdx 教程 Stage 2 的main/BUILD文件也是如此cc_binary( name hello-world, srcs [hello-world.cc], deps [ :hello-greet, ], )同包引用还能更省略根据 docs/concepts/labels.mdx当标签引用的就是当前所在包时包名以及冒号都可以省略。因此以下三种写法在包my/app/main内部是等价的app_binary :app_binary //my/app/main:app_binary惯例上文件引用通常省略冒号如hello-lib.cc规则引用通常保留冒号如:hello-lib但这只是书写约定语法上并无强制区别。省略包名的等价规则当冒号后的目标名与包路径的最后一段相同时目标名和冒号都可以省略。例如以下两个标签等价//my/app/lib //my/app/lib:lib这意味着//foo/bar/wiz永远是//foo/bar/wiz:wiz的简写——即使根本不存在foo/bar/wiz这个包它也绝不会被解释为//foo:bar/wiz。一个常见误区//my/app不等于“包里的所有目标”//my/app这类字符串在 Bazel 期待标签的上下文中等价于//my/app:app——它命名的是my/app包中名为app的目标并不是指代整个包或包内全部目标。这是BUILD文件中非常典型的一类错误docs/concepts/labels.mdx 专门对此做了强调。不过在package_group规范或.bzl文件中//my/app表示包本身的用法是被鼓励的因为它能清晰传达“包名是绝对的、扎根于工作区顶层目录”的含义。相对标签不能跨包引用相对标签不带//与包名的写法只能引用当前包内的目标绝不能用相对路径去引用其他包的目标。假设源树中有两个包my/app和my/app/testdata各自都有BUILD文件后者包内有一个文件testdepot.zip。在//my/app:BUILD中引用它正确与错误的写法分别是# 错误testdata 是另一个包不能用相对路径 testdata/testdepot.zip # 正确必须写全路径 //my/app/testdata:testdepot.zip跨包引用必须完整给出仓库标识符与包名。这也是为什么多包项目里跨包deps都要写全标签例如 docs/tutorials/cpp-use-cases.mdx 中的测试目标cc_test( name hello-test, srcs [hello-test.cc], deps [ googletest//:gtest_main, //main:hello-greet, ], )其中//main:hello-greet是工作区内跨包引用googletest//:gtest_main则是带仓库名前缀的外部仓库引用。带仓库名的完整标签形式上述讨论都默认目标位于当前仓库。当涉及外部仓库时标签前面还要加上仓库名myrepo//my/app/main:app_binary其中myrepo称为表象仓库名apparent repo name其解析结果可能因上下文而异。Bazel 还支持更严格的规范仓库名canonical repo name使用双前缀myrepo//my/app/main:app_binary规范仓库名在工作区内全局唯一能无歧义地定位目标。在同一个仓库内引用该仓库自身的目标时仓库名部分可以省略——这就是我们前面一直讨论的//path/to/package:target-name形式。还有一点值得注意//开头的标签是对**主仓库main repository**的引用即使从外部仓库中使用也依然指向主仓库。因此从外部仓库的角度看//a/b/c与//a/b/c含义不同——前者指回主仓库后者则在外部仓库自身内查找。这一点在编写会被外部仓库复用的规则时尤为关键。词法规范目标名与包名的合法字符为了让标签便于在 shell 中使用、易于被工具和脚本如 Bazel 查询语言处理Bazel 对标签的字符集有明确约束**目标名target-name**只能由以下字符组成a–z, A–Z, 0–9, 以及标点 !%-^_#$()*-,;?[]{|}~/.文件名形式的路径必须为规范形式的相对路径不能以/开头或结尾/foo、foo/均非法不能包含连续斜杠foo//bar非法禁止..上跳引用与./当前目录引用。**包名package-name**则要求允许小写字母a–z、大写字母A–Z、数字0–9及一系列标点符号含空格字符以及目录分隔符/不能以/开头或结尾不能包含子串//不能包含/./、/../、/.../等子串以避免逻辑包名与物理目录名转换时产生歧义。实操层面对于目录结构与模块体系强相关的语言如 Java建议包目录名选用语言合法的标识符避免以数字开头及特殊字符虽然 Bazel 支持工作区根包中的目标如//:foo但最好让根包保持为空使所有有意义的包都拥有描述性的名称。实战验证构建与查询中的标签标签最终要落实到命令与BUILD文件中。以下是贯穿官方 C 教程的可执行示例详见 docs/start/cpp.mdxbazel build //main:hello-world其中//main:是BUILD文件相对工作区根的位置hello-world是BUILD文件中的目标名。构建成功后产物位于工作区根下的bazel-bin/main/hello-world。多包场景下跨包依赖通过完整标签建立。Stage 3 的main/BUILD中cc_binary( name hello-world, srcs [hello-world.cc], deps [ :hello-greet, //lib:hello-time, ], )//lib:hello-time将main包的目标与lib包的目标连接起来。要让构建成功lib/BUILD中的hello-time还必须通过visibility显式对外开放——默认情况下目标只对同一BUILD文件内的其他目标可见cc_library( name hello-time, srcs [hello-time.cc], hdrs [hello-time.h], visibility [//main:__pkg__], )标签同样可以用于检查依赖关系。在 docs/tutorials/cpp-dependency.mdx 中通过bazel query结合标签可以导出目标的依赖图bazel query --notool_deps --noimplicit_deps deps(//main:hello-world) \ --output graph将输出粘贴到 GraphViz 即可可视化在 Ubuntu 上也可以安装graphviz与xdot后直接查看sudo apt update sudo apt install graphviz xdot xdot (bazel query --notool_deps --noimplicit_deps deps(//main:hello-world) \ --output graph)下图展示了 Stage 3 项目通过标签建立起的跨包依赖关系——//main:hello-world依赖//main:hello-greet与//lib:hello-time延伸阅读标签概念详解含仓库名、规范形式、词法规范docs/concepts/labels.mdxC 项目构建入门教程标签的实际构建用法docs/start/cpp.mdx依赖图的生成与可视化docs/tutorials/cpp-dependency.mdx常见 C 构建用例跨包deps与visibility实践docs/tutorials/cpp-use-cases.mdx标签可见性机制docs/concepts/visibility.mdx仓库内可直接参考的完整示例examples/cpp/BUILD 与 examples/BUILD【免费下载链接】bazela fast, scalable, multi-language and extensible build system项目地址: https://gitcode.com/GitHub_Trending/ba/bazel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考