工作区、软件包和目标

Bazel 会根据源代码构建软件,这些源代码以目录树的形式组织,称为工作区。工作区中的源文件以嵌套的软件包层次结构组织,其中每个软件包都是一个目录,包含一组相关的源文件和一个 BUILD 文件。BUILD 文件指定可以根据源代码构建哪些软件输出。

工作区

工作区是文件系统上的目录树,其中包含要构建的软件的源文件。每个工作区都有一个名为 WORKSPACE的文本文件,该文件可能为空,也可能包含构建输出所需的外部 依赖项的引用。

包含名为 WORKSPACE 的文件的目录被视为工作区的根目录。因此,Bazel 会忽略工作区中以包含 WORKSPACE 文件的子目录为根的任何目录树,因为它们会形成另一个工作区。

Bazel 还支持将 WORKSPACE.bazel 文件作为 WORKSPACE 文件的别名。如果这两个文件都存在,则使用 WORKSPACE.bazel

代码库

代码以代码库的形式组织。包含 WORKSPACE 文件的目录是主代码库的根目录,也称为 @。其他(外部)代码库在 WORKSPACE 文件中使用工作区规则定义,或从 Bzlmod 系统中的模块和扩展程序生成。如需了解详情,请参阅外部 依赖项概览

Bazel 捆绑的工作区规则记录在 Workspace Rules 部分的 Build Encyclopedia 中,以及有关 embedded Starlark repository rules 的文档中。

由于外部代码库本身就是代码库,因此它们通常也包含 WORKSPACE 文件。不过,Bazel 会忽略这些额外的 WORKSPACE 文件。特别是,以传递方式依赖的代码库不会自动添加。

软件包

代码库中的主要代码组织单元是软件包。软件包是一组相关文件,以及如何使用这些文件生成输出制品的规范。

软件包定义为包含名为 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

目标

软件包是目标的容器,这些目标在软件包的 BUILD文件中定义。大多数目标都是两种主要类型之一,即文件和规则。

文件又分为两种。源文件通常由人工编写,并签入到代码库中。生成的文件( 有时称为派生文件或输出文件)不会签入,而是 根据源文件生成。

第二种目标使用规则声明。每个规则实例都指定一组输入文件和一组输出文件之间的关系。规则的输入可以是源文件,也可以是其他规则的输出。

规则的输入是源文件还是生成的文件在大多数情况下并不重要;重要的是文件的内容。因此,您可以轻松地将复杂的源文件替换为规则生成的生成文件,例如,当手动维护高度结构化文件的负担变得过于繁琐,并且有人编写程序来派生该文件时。 无需更改该文件的使用者。相反,只需进行本地更改,即可轻松地将生成的文件替换为源文件。

规则的输入还可以包括其他规则。此类关系的具体含义通常非常复杂,并且取决于语言或规则,但直观上很简单:C++ 库规则 A 可能有另一个 C++ 库规则 B 作为输入。此依赖项的效果是,B 的头文件在编译期间可供 A 使用,B 的符号在链接期间可供 A 使用,B 的运行时数据在执行期间可供 A 使用。

所有规则的一个不变量是,规则生成的文件始终与规则本身属于同一软件包;无法将文件生成到另一个软件包中。不过,规则的输入来自另一个软件包的情况并不少见。

软件包组是一组软件包,其目的是限制对某些规则的访问权限。软件包组由 package_group 函数定义。它们具有三个属性:所包含的软件包列表、名称以及包含的其他软件包组。引用它们的唯一允许方式是来自规则的 visibility属性或来自default_visibility属性的 package函数;它们不会生成或使用文件。如需了解详情,请参阅 package_group 文档

标签