简介
Bazel根据在称为工作空间的目录中组织的源代码构建软件。 工作空间中的源文件以包的嵌套层次结构进行组织,其中每个包都是包含一组相关源文件和一个BUILD文件的目录。 BUILD文件指定可以从源构建哪些软件输出。
Workspace, packages and targets
工作空间 (Workspace)
工作空间是文件系统上的目录,其中包含要构建的软件的源文件,以及指向包含构建输出的目录的符号链接。 每个工作空间目录都有一个名为 WORKSPACE 的文本文件,该文件可以为空,或者可以包含对构建输出所需的外部依赖项的引用。
包含名为 WORKSPACE 的文件的目录被视为工作空间的根。 因此,Bazel 会忽略以包含 WORKSPACE
文件的子目录为根的工作空间中的任何目录树(因为它们形成另一个工作空间)。
Bazel 还支持 WORKSPACE.bazel 文件作为 WORKSPACE 文件的别名。 如果两个文件都存在,则 WORKSPACE.bazel 将具有优先权。
仓库 (Repositories)
代码在仓库中组织。 包含 WORKSPACE 文件的目录是主存储库的根,也称为@。 其他(外部)存储库是使用工作区规则在 WORKSPACE 文件中定义的。
与 Bazel 捆绑在一起的工作空间规则记录在 Build Encyclopedia 的“工作空间规则”部分以及有关嵌入式 Starlark 存储库规则的文档中。
由于外部仓库本身就是仓库,因此它们通常也包含 WORKSPACE 文件。 但是,Bazel 将忽略这些其他 WORKSPACE 文件。 特别是,不会自动添加依赖于传递的仓库。
包 (Packages)
仓库中代码组织的主要单位是包。 包是相关文件的集合,以及它们之间的依赖性说明。
包定义为一个目录,其中包含一个名为 BUILD 或 BUILD.bazel 的文件,位于工作空间的顶级目录下。 包括其目录中的所有文件,以及其下的所有子目录,但那些子目录本身包含 BUILD 文件。
例如,在下面的目录树中,有两个软件包 my/app 和子软件包 my/app/ tests。 请注意,my/app/data 不是软件包,而是属于软件包 my/app 的目录。
src/my/app/BUILD
src/my/app/app.cc
src/my/app/data/input.txt
src/my/app/tests/BUILD
src/my/app/tests/test.cc
目标 (Targets)
包是容器。 包的元素称为目标。 大多数目标是文件和规则这两种主要类型之一。 此外,还有另一种目标,即包组,但数量却要少得多。
文件进一步分为两种。 源文件通常是在人们的努力下编写的,并检入到存储库中。 生成的文件(有时称为派生文件)未检入,而是由构建工具根据特定规则从源文件生成的。
第二类目标是规则。 规则指定一组输入和一组输出文件之间的关系,包括从输入派生输出的必要步骤。 规则的输出始终是生成的文件。 规则的输入可能是源文件,但也可能是生成的文件。 因此,一条规则的输出可能是另一条规则的输入,从而可以构建较长的规则链。
在大多数情况下,规则输入是源文件还是生成文件都是无关紧要的。 重要的只是该文件的内容。 这个事实使用规则生成的生成文件替换复杂的源文件变得很容易,例如,当手动维护高度结构化的文件的负担变得太累,而有人编写程序来派生该文件时,就会发生这种情况。 该文件的使用者不需要更改。 相反,生成的文件很容易被仅具有本地更改的源文件替换。
规则的输入也可以包括其他规则。 这种关系的确切含义通常非常复杂,并且依赖于语言或规则,但是从直观上讲很简单:C++ 库规则A可能有另一个 C++ 库规则 B 用于输入。 这种依赖性的结果是,在编译期间 B 的头文件对 A 可用,在链接期间 B 的符号对 A 可用,而在执行期间 B 的运行时数据对 A 可用。
所有规则的不变之处在于,规则生成的文件始终与规则本身属于同一包; 无法将文件生成到另一个包中。 但是,规则的输入来自另一个程序包并不少见。
包组是一组包,其目的是限制某些规则的可访问性。 包组由 package_group 函数定义。 它们具有两个属性:它们包含的软件包列表及其名称。 引用它们的唯一允许方式是来自规则的可见性属性或包函数的 default_visibility 属性。 它们不生成或使用文件。 有关更多信息,请参阅“构建百科全书”的相应部分。
标签 (Labels)
所有目标完全属于一个包。 目标的名称称为其标签,标准格式的典型标签如下所示:
@myrepo//my/app/main:app_binary
在标签引用它所在的相同仓库的典型情况下,可能会忽略仓库名称。 因此,在 @myrepo 内部,此标签通常写为:
//my/app/main:app_binary
每个标签都有两部分,包名称(my/app/main)和目标名称(app_binary)。 每个标签都唯一标识一个目标。 标签有时以其他形式出现; 如果省略冒号,则假定目标名称与程序包名称的最后一个组成部分相同,因此这两个标签是等效的:
//my/app
//my/app:app
标签的词汇规范 (Lexical specification of a Label)
标签的语法是故意严格的,以禁止对 shell 具有特殊含义的元字符。 这有助于避免无意的引号问题,并使得构建用于操纵标签的工具和脚本(例如 Bazel Query Language)更加容易。 允许的目标名称的详细信息如下:
目标名字://…:target-name
包名字://package-name:…
Rules
规则指定输入和输出之间的关系,以及构建输出的步骤。 规则可以是许多不同种类或类中的一种,它们可以生成编译的可执行文件和库,测试可执行文件和其他受支持的输出,如 构建百科全书 中所述。
每个规则都有一个由 name 属性指定的字符串类型的名称。 该名称必须是语法有效的目标名称,如上所述。 在某些情况下,名称有些随意,而由规则生成的文件的名称更有趣。 属实是正确的。 在其他情况下,名称是有意义的:例如,对于 _binary 和 _test 规则,规则名称确定构建生成的可执行文件的名称。
cc_binary(
name = "my_app",
srcs = ["my_app.cc"],
deps = [
"//absl/base",
"//absl/strings",
],
)
每个规则都有一组属性。 给定规则的适用属性以及每个属性的重要性和语义是规则类别的函数;有关规则及其对应属性的列表,请参见构建百科全书。 每个属性都有一个名称和一个类型。 属性可以具有的一些常见类型是整数,标签,标签列表,字符串,字符串列表,输出标签,输出标签列表。 并非在每个规则中都需要指定所有属性。 因此,属性形成了一个从键(名称)到可选的,键入的值的字典。
许多规则中存在的 srcs 属性的类型为“标签列表”; 其值(如果存在)是标签列表,每个标签都是作为该规则输入的目标名称。
许多规则中存在的 outs 属性的类型为“输出标签列表”; 这与 srcs 属性的类型相似,但是在两个重要方面有所不同。 首先,由于规则的输出与规则本身属于同一包,因此输出标签不能包含包组件。 它们必须采用上面显示的“相对”形式之一。 其次,(普通)标签属性所隐含的关系与输出标签所隐含的关系相反:一个规则取决于其 srcs ,而另一个规则取决于其 outs。 因此,两种类型的标签属性将方向分配给目标之间的边缘,从而产生依赖图。