Bazel应用方法
Bazel简单应用
1.创建工作空间workspace
工作空间是一个保留你工程的源文件以及Bazel build输出的目录。
创建方法为:指定一个目录作为Bazel工作空间,创建一个名为WORKSPACE
的空文件在该目录下。
当Bazel编译工程时,所有的输入和依赖必须在相同的workspace下。
2.书写BUILD文件
在github上可以下载bazel教程包含一些例子。
git clone https://github.com/bazelbuild/examples
一个BUILD文件包含几个不同类型的bazel指令。
最重要的类型是build rule
,告知Bazel如何去build想要的输出,比如execuatable binaries或者libraries。
每一个BUILD文件中的build rule
叫做一个target
,该target
指向对应的源文件或依赖集合。一个target
也可以指向其他target
。
参考examples/cpp-tutorial/stage1/main
目录下的一个简单的BUILD文件。里面仅包含一个target和一个build rule。
在这个例子中,hello-world
target示例cc_binaries规则,该规则告知Bazel根据hello-world.cc
源文件去build一个可执行binary。
其中targetsrc
表明Bazel build的target是哪个源文件。
3.编译工程
拿着教程的例子来尝试编译。将目录转到examples/cpp-tutorial/stage1
下,跑以下命令:
bazel build //main:hello-world
注意到target label,//main:
部分是该BUILD文件相对于workspace根目录的位置,hello-world
是我们命名的target。
之后Bazel会输出以下类似的消息:
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 2.267s, Critical Path: 0.25s
表明你编译成功。Bazel将build的输出放在workspace根下的bazel-bin
目录下。
编译成功后会生成一个可执行文件,可以输入以下command:
bazel-bin/main/hello-world
4.可视化文件依赖图
生成一个表示依赖图的text,在workspace的根目录下运行command:
bazel query --notool_deps --noimplicit_deps 'deps(//main:hello-world)' \
--output graph
上述command告知Bazel去寻找对于target//main:hello-world
的所有依赖,并表示成一个图。
接着paste the text into GraphViz
现在我们已经建立了workspace,built我们的project,检查了我们的依赖。让我们来些更复杂的吧。
Refine your Bazel build
当一个单一的target对于一个小project已经足够,我们会想要将一个大工程拆分成几个targets和packages,使得每次只需编译更改的部分,来加速builds。
1.详细的多重build targets
以官方教程来做例子,以下为cpp-tutorial/stage2/main
目录下的BUILD文档:
在这个BUILD文档中,Bazel首先编译hello-greet
library,接着是hello-world
binary。在hello-world
target中的deps属性,告知Bazel,编译hello-world
binary需要hello-greet
library。
接下来我们需要编译我们的工程,转到cpp-tutorial/stage2
目录下,运行以下conmand:
bazel build //main:hello-world
同样会生成以下信息:
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 2.399s, Critical Path: 0.30s
接着可以运行可执行文件:
bazel-bin/main/hello-world
如果这时你修改了hello-greet.cc
,并rebuild the project,Bazel将会仅仅重新编译该file。
以上,我们现在已经build过包含两个target的project。
2.应用多重packages
我们将工程分成多个packages,比如官方教程cpp-tutorial/stage3
的目录内容:
上图中,一个project包含两个子目录(sub-directories),每个目录都包含一个BUILD文件。对于Bazel来说,这个workspace包含两个packages,lib和main。
其中lib/BUILD文档:
main/BUILD文档:
As we can see,在main package中的 hello-world
target依赖lib包中的 hello-time
(因此在deps中写作//lib:hello-time
)。
Dependency Graph:
注意到我们将lib/BUILD
中的//lib:hello-time
target对于main/BUILD
target清晰地可视化,通过visibility
属性。因为默认target只会将在同一个BUILD文档中的target可视化。(Bazel使用target visibility来防止像公有API中库的实现细节的泄露等情况)
接着我们来编译该工程,切换目录到cpp-tutorial/stage3
and run the following command:
bazel build //main:hello-world
输出:
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 0.167s, Critical Path: 0.00s
最后运行:
bazel-bin/main/hello-world
以上,我们已经build过包含两个package的project。
3.应用labels对于引用的targets
Bazel应用labels对于引用的targets,例如://main:hello-world
or//lib:hello-time
语法为:
//path/to/package:target-name
如果target是一个规范的target,则path/to/package
是到包含BUILD文档的目录,target-name
就是在BUILD文档中命名的target。
如果target是一个file target,则path/to/package
是到package的根目录,target-name
就是target file的名字。
如果该target在仓库的根目录,the package path is empty,只需要//:target-name
。当该target与原先target位于用一个BUILD文档,则可直接跳过//,仅仅用:target-name
。
参考:
Bazel官网