Bazel 会根据源代码构建软件,这些源代码以目录树的形式(称为代码库)进行整理。工作区由一组已定义的代码库组成。代码库中的源文件以嵌套的软件包层次结构进行组织,其中每个软件包都是一个目录,包含一组相关的源文件和一个 BUILD
文件。BUILD
文件用于指定可从源代码构建哪些软件输出。
代码库
Bazel build 中使用的源文件会整理到代码库(通常简称为 repo)中。repo 是一个目录树,其根目录中包含边界标记文件;此类边界标记文件可以是 MODULE.bazel
、REPO.bazel
,或者在旧版环境中可以是 WORKSPACE
或 WORKSPACE.bazel
。
运行当前 Bazel 命令的仓库称为主仓库。其他(外部)代码库由 repo 规则定义;如需了解详情,请参阅外部依赖项概览。
工作区
工作区是指从同一主代码库运行的所有 Bazel 命令共享的环境。它包含主代码库和所有已定义的外部代码库。
请注意,从历史上看,“代码库”和“工作区”的概念一直混为一谈;“工作区”一词通常用于指代主代码库,有时甚至用作“代码库”的同义词。
软件包
代码库中的主要代码组织单元是软件包。软件包是一组相关文件,以及有关如何使用这些文件来生成输出制品的规范。
软件包是指包含 BUILD
文件(名为 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 作为输入。此依赖项的效果是,在编译期间,A 可以使用 B 的头文件;在链接期间,A 可以使用 B 的符号;在执行期间,A 可以使用 B 的运行时数据。
所有规则的一个不变量是,规则生成的文件始终属于与规则本身相同的软件包;无法将文件生成到另一个软件包中。不过,规则的输入来自其他软件包的情况并不少见。
软件包组是一组软件包,其目的是限制某些规则的可访问性。软件包组由 package_group
函数定义。它们具有三个属性:所包含的软件包列表、名称以及所包含的其他软件包组。引用它们的唯一允许方式是通过规则的 visibility
属性或 package
函数的 default_visibility
属性;它们不会生成或使用文件。如需了解详情,请参阅 package_group
文档。