bazel工具是Google内部构建工具Blaze的开源实现,属于编译打包工具,和maven、ant等类似。
构建系统时,程序员一般写一个buildfile文件来描述系统,通常buildfile命名为BUILD。
cc_library(
name = "hdmap_input",
srcs = ["hdmap_input.cc"],
hdrs = ["hdmap_input.h"],
deps = [
"//modules/common/math:geometry",
"//modules/map/hdmap",
# For personal convenience, some dependencies are omitted here.
......
"//modules/perception/lib/config_manager",
],
)
cc_test(
name = "hdmap_input_test",
size = "small",
srcs = ["hdmap_input_test.cc"],
deps = [
":hdmap_input",
"@com_google_googletest//:gtest_main",
......
"//modules/perception/lib/config_manager",
],
)
在Bazel中,BUILD文件定义了targets。上面的两个targets分别是cc_library和cc_test。每个target对应着Bazel能够创建的一种制品(artifact)。
其中library能够生成被其他library或者others所使用的内容,test能够生产测试library或者其他的文件。
每个target都有一个name属性,方便它在命令行和其他target中被引用。src属性是必须被编译的相关源文件,用来生成对应的target artifact。deps属性是前置必须先构建或链接的依赖。【依赖关系可以限制在当前的packege以内(例如,hdmap_input_test依赖:hdmap_input),也可以是在同一个源代码层级中的不同package(例如,hdmap_input_test依赖于//modules/perception/lib/config_manager),或者源代码层级之外的第三方artifact(例如,hdmap_input_test依赖于@com_google_googletest//:gtest_main)。】
每个源代码层级(source hierarchy)都被称为一个workspace,并由根目录下的一个WORKSPACE文件来标示。
和Ant一样,用户也需要使用bazel的命令行工具来进行构建。例如,为了构建hdmap_input这个target,用户需要执行:
bazel build :hdmap_input
在首次运行上面的命令的时候,bazel工具会执行下面工作:
(1)解析当前workspace中的每一个BUILD文件,创建各个artifact之间的依赖关系图;
(2)用上面创建的图来决定hdmap_input的依赖转换关系,即hdmap_input所依赖的每个target,及每个target依赖的其他target,如此递归;
(3)根据具体的定义,按顺序构建或下载每一个依赖。bazel工具在这里首先会构建没有任何依赖的target,并保持跟踪对于每个target来说还有哪些依赖需要构建。一旦一个target的所有依赖都已经构建好了以后,bazel就开始构建该target。该过程持续到hdmap_input的每一个依赖都被构建完成。
(4)链接所有上一步中所生成的依赖,构建hdmap_input来生成最后的可执行二进制文件。
bazel的其他相关技巧
- 对工具的依赖
很多构建都依赖于安装在自己机器上的各种工具,由于工具版本和安装环境等因素,实现跨机器的构建就会变得比较困难。如果项目还使用了不同的语言,并针对不同平台进行构建或编译,而每个平台要求略有差异的工具来完成相似工作,这个问题就更加明显。(这里涉及到两个问题:环境依赖和平台针对性。)
bazel处理第一个问题的方式是把工具作为target所依赖的一部分。当前workspace中每个cc_library依赖于一个编译器,但也可以在workspace层面进行配置。每次当bazel构建一个library的时候,它首先检查特定的编译器是否在已知位置存在,如果没有的话首先下载。和其他依赖一样,如果编译器发生变化,所有依赖于它的artifact都需要重建。bazel中定义的每一类target都是用同样的策略来声明它需要运行的工具,确保无论什么样的环境下bazel都能够正确初始化。
bazel解决第二个平台独立性问题的方式是使用工具链。targets并不直接依赖于工具本身,而是依赖于工具链的类型。一个工具链包括一组工具和其他相关属性,用于定义某个类型的target如何在特定平台上构建。workspace可以根据主机和目标平台定义所使用的特定工具链。
- 扩展构建系统
bazel允许通过自定义规则(custom rules)来扩展所支持的target类型。
要定义一个bazel的rule,首先要定义rule需要的input(以BUILD文件中传递的参数形式)和该rule所生成的output。并且还要定义该rule所要生成的actions。每个action同样也要声明input和output,运行一个特定可执行文件或在文件中写入特定字符串,并能够通过input/output连接到其他的action。这也意味着在bazel里面,action是最底层的可编辑单元(lowest-level composable unit)–只要一个action只使用它所声明的input/output,它就能做任何它想做的事情,而bazel则会负责对action进行规划安排并在合适的时候缓存其执行结果。
#########################################
bazel常用命令
#########################################
首先要有一个workspace,即WORKSPACE文件(每个bazel项目对应一个WORKSPACE文件。注意在bazel中,WORKSPACE指的是一个包括了单个或多个项目所有源文件的目录,然后在这个目录下要放一个WORKSPACE文件)。
其次要有一个BUILD文件,其描述了构建输出及依赖。
使用bazel构建程序
构建一个目标
输入bazel build,后跟要构建的目标。
$ bazel build //foo
发出构建 //foo
的命令后,会看到类似于以下内容的输出:
INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
bazel-bin/foo/foo
INFO: Elapsed time: 9.905s, Critical Path: 3.25s
INFO: Build completed successfully, 6 total actions
构建多个目标
bazel允许通过多种方式指定要构建的目标,这些统称为“目标模式”。
以 //
开头的所有目标模式都将相对于当前工作区workspace进行解析。
//foo/bar:wiz | 只有一个目标 //foo/bar:wiz |
---|---|
//foo/bar | 等同于//foo/bar:bar |
//foo/bar:all | 软件包foo/bar中的所有规则目标 |
//foo/… | foo目录下所有软件包中的所有规则目标 |
//foo/…:all | foo目录下所有软件包中的所有规则目标 |
//foo/…: * | foo目录下所有软件包中的所有目标(规则和文件) |
//foo/…:all-targets | foo目录下所有软件包中的所有目标(规则和文件) |
//… | 工作区中所有软件包的目标,这不包括外部代码库中的目标 |
//…:all | 顶级软件包中的所有目标(如果workspace的根目录存在BUILD文件) |
不以 //
开头的目标模式相对于当前工作目录进行解析。
:foo | 等同于//foo:foo |
---|---|
bar:wiz | 等同于//foo/bar:wiz |
bar/wiz | 等同于:### 如果foo/bar/wiz是软件包,则为//foo/bar/wiz:wiz ### 如果foo/bar是软件包,则为//foo/bar:wiz ### 否则为//foo:bar/wiz |
bar:all | 等同于//foo/bar:all |
:all | 等同于//foo:all |
…:all | 等同于//foo/…:all |
… | 等同于//foo/…:all |
bar/…:all | 等同于//foo/bar/…:all |
foo/...
是package是上方的通配符,表示以递归方式在 foo 目录下(针对软件包路径的所有根目录)的所有软件包。:all
是目标上方的通配符,用于匹配软件包中的所有规则。
这两种字符可以组合使用,如在 foo/...:all
中一样。当同时使用这两个通配符时,这可以简化为 foo/...
。
此外, :*
(或 :all-targets
)是与匹配的软件包中的每个目标(包括通常不由任何规则构建的文件)匹配的通配符。
这意味着 :*
表示 :all
的超集。:all
通配符用于典型构建。
bazel还支持使用斜杠代替标签语法所需的冒号;在使用Bash文件名扩展时,这通常很方便。例如,foo/bar/wiz
等同于 //foo/bar:wiz
(如果有软件包 foo/bar
)或 //foo:bar/wiz
(如果存在软件包 foo
)。
许多bazel命令都接受目标模式列表作为参数,并且它们都遵循前缀否定运算符 -
。这可用于从上述参数指定的集合中减去一组目标。(注意:这意味着顺序很重要。)例如,
$ bazel build foo/... bar/...
指“在 foo
下构建所有目标,在 bar
下构建所有目标”,而
$ bazel build -- foo/... -foo/bar/...
指“构建 foo
下的所有目标,但不知 foo/bar
下”。(其中 --
参数是必需的,可以防止以 -
开头的后续参数被解释为其他选项。)
需要注意的是,以这种方式减去目标时,并不能保证它们不会被构建,因为它们可能是未减去的目标的依赖项。文章来源:https://www.toymoban.com/news/detail-569148.html
参考:
https://zhuanlan.zhihu.com/p/262497747
https://bazel.google.cn/versions/6.1.0/run/build?hl=fr&authuser=19#getting-help文章来源地址https://www.toymoban.com/news/detail-569148.html
到了这里,关于bazel工具入门(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!