当前位置: 首页 > 工具软件 > Bazel > 使用案例 >

bazel学习总结(一)

麹凯捷
2023-12-01

最近工作需要,开始学习bazel自动化构建工具,上网搜了搜并没有一个很系统的讲解文档,只有google的官方文档可以阅读,然而官方文档的组织多而杂乱,且不成体系,给入门造成了不小的困难,故准备凭我如今两周看了三遍文档的肤浅学习,系统的写一下这个系列的博客,供后人参考,也再让我自己整理一遍这些知识。

一、bazel是用来干啥的

bazel简单来说就是用来自动化构建大型工程的,和make, maven之类的工具属于一类东西,他的目标是当项目里的一部分程序修改后,只需要几个命令就可以将整个项目进行重新编译,且要求快。它还可以进行自动化测试,当然这些都必须由你来编写测试流程和规则。因为我们项目用的c++,而且bazel对c++的支持很完善,所以我的整个系列都只针对c++来说。

二、bazel的文件管理架构

bazel中对于文件架构的概念有两个:workspacepackage

workspace是表示整个项目的,也叫repo,必须在项目的根目录下建一个WORKSPACE文件来定义项目的根目录,bazel会忽略所有项目子目录下的WORKSPACE文件。

package是项目中的模块,也就是一个一个包,包在组织上比较随意,可以根据项目需求来定,你想哪个文件夹中的东西成为一个包,就在那个文件夹的目录里创建一个BUILD文件即可,包的管理范围包括子目录里的东西,但不包括子包所包括的内容。比如:

.../project/
	WORKSPACE
	lib/
		BUILD
		...
	src/
		BUILD
		...
		other1/
			BUILD
		other2/
			...

则lib, src以及other1都是packages,但other1目录里的东西不属于src包,但other2里的东西都属于src包。包和包之间的内容不重叠,不包含。
引用一个包写全了是这样的:

@[project_name]//[path/to/package]

比如上面的三个包:

@project//lib
@project//src
@project//src/other1

后面会提到其他简化写法,但我觉得一开始明白这个完整形态是很重要的。

三、bazel的运行架构

首先明白bazel的运行架构我觉得会让学习bazel做到心中有数。bazel自动化构建代码时大体分为三个步骤:

  1. 加载阶段:load phase
  2. 分析阶段:analysis phase
  3. 执行阶段:execution phase

加载阶段:
bazel在构建时我认为只会执行BUILD文件,这个文件可以理解成一个脚本,指导bazel如何去构建这个package中的代码,将他们变成二进制可执行文件。但bazel的文件其实不止只有WORKSPACEBUILD,还有很多.bzl文件,这些文件可以理解成类似于c里面的头文件一样,为了让BUILD文件看起来简洁,工整,所以把很多其他东西以及定义之类的内容,扔到了.bzl文件里,然后在BUILD文件开始处通过一个load命令将需要的东西包含进来,类似于#include,所以开发bazel的人限制了BUILD文件中可以使用的语法,而在.bzl文件中没有限制。

以上说的这些废话,就是在加载阶段完成的,加载阶段做的就是替换代码,展开代码,类似于#include干的事,还有一些比如宏(Macro)展开之类的事情也在这一阶段完成,宏在后面会说。

分析阶段:
加载阶段结束后,我觉得此时可以认为我们只有BUILD文件需要考虑了,而且是一个展开完全的BUILD文件,这其中都是一个一个的函数调用,每一个函数调用定义一个对象,每一个对象都包含一个label(这个label的概念很重要,他是bazel的一种基本数据结构,不是string那么简单),由name域的传参决定。这些对象功能各样,有的是定义了一个行为(称为rule,规则),有的是定义了一个文件或一组文件,有的定义了一组配置等等,后面细说。类似如下,不同的函数需要的参数也是不同的:

cc_binary(name="hahaha",srcs=["hello.cc"],deps=[":enenen"])
cc_library(name="enenen",srcs=[......],hdrs=[......])
config_setting(name="x86",values={"cpu","x86"})

分析阶段就是来执行这些函数,生成(我的理解)一个静态有向图,就好像tensorflow那个静态图的概念,每一个函数都生成静态图中的一个结点,根据结点中定义的label和其他信息,构建结点之间的依赖关系。比如上面那个"hahaha"是个label,“enenen"也是一个label,然后"hahaha"依赖于"enenen”。

分析阶段只是建立这种依赖关系的有向图,定义这些对象,但不会确切的执行任何构建工作,它只是分配了工作顺序,就好像一个工厂把人员各就各位了,但大家都没开始工作,等到execution phase,大家一起开工。

执行阶段
也就是老板喊了声 “各就各位,干”,然后大家每个对象就各司其职,自己不依赖别人的对象就直接开干了,依赖别人的对象就等别人干好了把需要的材料送过来再开干。所以在这个阶段才会开始构建项目,输出各种文件,执行各种IO操作。

-----------------------------------下一节开始细节------------------------------------------

 类似资料: