Bazel编译教程(基础篇)
如果你还在坚持CMake话,不妨尝试一下谷歌的高效编译工具--Bazel
- 前言
- 一、Bazel是什么?
- 二、安装bazel
- 三、介绍Bazel文件组成
- 1. WORKSPACE(工作区)
- 2. BUILD文件(packkage)
- 四、Bazel编译初探
- 1. 编译单个target
- 2. 编译多个target
- 3. 编译多个package
- 总结
前言
最近,发现公司大佬们都在偷偷使用Bazel构建工程项目,此时,我发现我在学校学习的Make已经不香了,于是我决定上车。
提示:以下是本篇文章正文内容,下面案例可供参考
一、Bazel是什么?
Bazel 是一个类似于 Make 的工具,是 Google 为其内部软件开发的特点量身定制的工具,如今 Google 使用它来构建内部大多数的软件。它的功能有诸多亮点:
- 多语言支持:目前 Bazel 默认支持 Java、Objective-C 和 C++,但可以被扩展到其他任何变成语言。
- 高级构建描述语言:项目是使用一种叫 BUILD 的语言来描述的,它是一种简洁的文本语言,它把一个项目视为一个集合,这个集合由一些互相关联的库、二进制文件和测试用例组成。相反,像 Make 这样的工具,需要去描述每个文件如何调用编译器。
- 多平台支持:同一套工具和相同的 BUILD 文件可以用来为不同的体系结构构建软件,甚至是不同的平台。在 Google,Bazel 被同时用在数据中心系统中的服务器应用和手机端的移动应用上。
- 可重复性:在 BUILD 文件中,每个库、测试用例和二进制文件都需要明确指定它们的依赖关系。当一个源码文件被修改时,Bazel 凭这些依赖来判断哪些部分需要重新构建,以及哪些任务可以并行进行。这意味着所有构建都是增量的,并且相同构建总是产生一样的结果。
- 可伸缩性:Bazel 可以处理大型项目;在 Google,一个服务器软件有十万行代码是很常见的,在什么都不改的前提下重新构建这样一个项目,大概只需要 200 毫秒。
对于为什么要重新发明一个构建工具而不直接使用 Make,Google 认为 Make 控制得太细,最终的结果完全依靠开发人员能正确编写规则。很久以前,Google 使用自动生成的臃肿的 Makefile 来构建他们的软件,速度太慢,结果不可靠,最终影响了研发人员的效率和公司的敏捷性。所以他们做了 Bazel。Bazel 的规则层次更高,比如,对于“Java 测试”、“C++ 二进制文件”,它都有定义好的内建规则,而这些规则都已经被无数的测试证明是正确和稳定的。
二、安装bazel
三、介绍Bazel文件组成
bazel中对于文件架构的概念有两个:workspace和package。
- workspace是表示整个项目的,也叫repo,必须在项目的根目录下建一个WORKSPACE文件来定义项目的根目录,bazel会忽略所有项目子目录下的WORKSPACE文件。
- package是项目中的模块,也就是一个一个包,包在组织上比较随意,可以根据项目需求来定,你想哪个文件夹中的东西成为一个包,就在那个文件夹的目录里创建一个BUILD文件即可,包的管理范围包括子目录里的东西,但不包括子包所包括的内容。比如:
.../project/WORKSPACElib/BUILD...src/BUILD...other1/BUILDother2/...
lib,src和other1分别为一个包,但是other1中含有一个BUILD,因此other1中有一个子包(上文提到:子包不属于父包),所以other1里面的东西不属于src包,但是other2里面的东西属于src包。
1. WORKSPACE(工作区)
WORKSPACE是Bazel一个概念,它实质上是一个目录。这个目录是bazel工作时的一个基准目录。
Bazel规定,项目源文件和Bazel构建出的目标文件,均放在此目录。要把一个目录设置为WORKSPACE, 则必须在此目录创建一个新的空文件,名为WORKSPACE. Bazel构建项目时,所有的输入项和依赖项,必须位于同一个工作区内。每个工作目录内,可以有多个项目(目录)。bazel 编译或者执行其它命令时,是在WORKSPACE中。
2. BUILD文件(packkage)
BUILD文件的作用类似 Makefile之于Make, xml文件之于Maven, gradle文件之于Gradle. BUILD文件中包含bazel的各种不同类型的指令,其中包含构建规则,它指出Bazel如何利用给定的输入,构建出指定的输出。如利用什么.cpp文件,构建出库或者可执行程序。BUILD文件中的每一条编译指令被称为一个target,它指向一系列的源文件和依赖,一个target也可以指向别的target。
举个例子,下面这个hello-world的target利用了Bazel内置的cc_binary编译指令,来从hello-world.cc源文件(没有其他依赖项)构建一个可执行二进制文件。指令里面有些属性是强制的,比如name,有些属性则是可选的,srcs表示的是源文件。
cc_binary(name = "hello-world",srcs = ["hello-world.cc"],
cc_binary即声明了一个构建规则,用于编译生成一个可执行文件。可执行文件名(目标名)由name属性指定,name属性的值的类型可以看出是string类型。srcs属性指定了源文件,srcs属性的值的类型可以看出是list of strings。
*_binary 规则:指定生成相应语言的可执行程序。cc_binary表示c++可执行程序,jave_binary表示java可执行程序。
*_library 规则:指定生成相应语言的库。
*_test 规则:是一个特殊的bianry规则,通常用于自动化测试。
四、Bazel编译初探
Bazel提供了一些编译的例子,在https://github.com/bazelbuild/examples/,可以clone到本地试一下。其中examples/cpp-tutorial目录下包含了这么些文件:
cpp-tutorial
│ ├── README.md
│ ├── stage1
│ │ ├── main
│ │ │ ├── BUILD
│ │ │ └── hello-world.cc
│ │ ├── README.md
│ │ └── WORKSPACE
│ ├── stage2
│ │ ├── main
│ │ │ ├── BUILD
│ │ │ ├── hello-greet.cc
│ │ │ ├── hello-greet.h
│ │ │ └── hello-world.cc
│ │ ├── README.md
│ │ └── WORKSPACE
│ └── stage3
│ ├── lib
│ │ ├── BUILD
│ │ ├── hello-time.cc
│ │ └── hello-time.h
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-greet.cc
│ │ ├── hello-greet.h
│ │ └── hello-world.cc
│ ├── README.md
│ └── WORKSPACE
可以看到3个stage,分别为了三个项目例子,由简到繁。
1. 编译单个target
编译stage1:
首先进入到cpp-tutorial/stage1目录下,然后运行以下指令:
bazel build //main:hello-world
注意target中的//main:是BUILD文件相对于WORKSPACE文件的位置,hello-world则是我们在BUILD文件中命名好的target的名字。
然后Bazel就会有一些类似这样的输出:
至此,编译成功,编译结果输出在bazel-bin/main/文件夹中。
注:bazek clean 清空编译结果
查看依赖图
bazel query --nohost_deps --noimplicit_deps 'deps(//main:hello-world)' \--output graph
2. 编译多个target
在这个BUILD文件中,Bazel首先编译了hello-greet这个库(利用Bazel内置的cc_library编译指令),然后编译hello-world这个二进制文件。hello-world这个target的deps属性告诉Bazel,要构建hello-world这个二进制文件需要hello-greet这个库,编译过程同上,此处省略。。。
结论:发现hello-world在编译时候的结构和之前有所不同,现在是有两个targets。hello-world这个target从一个源文件编译而来,同时依赖于另一个target//main:hello-greet,这个target又是从两个源文件编译而来。
3. 编译多个package
编译过程省略。。。
结论:可以看出hello-world这个mainpackage中的target依赖于lib package中的hello-time target(即target label为://lib:hello-time)- Bazel是通过deps这个属性知道自己的依赖项的。
总结
以上内容就是对bazel的简单学习和总结,方便以后复习。总而言之:bazel的使用就是为了针对大的工程项目而提高效率的,并且可以发现,bazel相比写cmakelists简便多了。
Bazel编译教程(基础篇)相关推荐
- 基于c++和asio的网络编程框架asio2教程基础篇:1、基本概念和使用说明
基于c++和asio的网络编程框架asio2教程基础篇:1.基本概念和使用说明 由于asio2没有写技术文档,因此打算写几篇文章介绍一下如何使用它,主要是针对新手. 1.asio2如何使用? asio ...
- ESP32-C3入门教程 基础篇⑪——Non-Volatile Storage (NVS) 非易失性存储参数的读写
文章目录 一.前言 二.NVS介绍 三.操作流程 3.1 读操作流程 3.2 写操作流程 四.关键函数 五.随机整数 读写示例 六.对象/数组 读写示例 七.总结 八.参考 一.前言 本文基于VS C ...
- ESP32-C3入门教程 基础篇②——GPIO口输入,按键的长按和短按
文章目录 一.前言 二.硬件准备 三.知识要点 3.1 GPIO使用 3.2 时钟节拍 四.参考例程 五.功能简述 六.源码实现 6.1 中断方式 6.2 定时扫描 七.源码详解 一.前言 本文基于V ...
- Midjourney|文心一格prompt教程[基础篇]:注册使用教程、风格设置、参数介绍、隐私模式等
Midjourney|文心一格prompt教程[基础篇]:注册使用教程.风格设置.参数介绍.隐私模式等 开头讲一下为什么选择Midjourney和文心一格,首先Midjourney功能效果好不多阐述: ...
- 基于c++和asio的网络编程框架asio2教程基础篇:2、各个回调函数的触发顺序和执行流程
基于c++和asio的网络编程框架asio2教程基础篇:2.各个回调函数的触发顺序和执行流程 以tcp举例: tcp服务端流程: #include <asio2/asio2.hpp>int ...
- 付呗聚合支付快速教程 基础篇①——基本介绍和配置
文章目录 一.对接手册 二.商户后台 三.银行分账 四.其他介绍 一.对接手册 付呗聚合支付对接手册 第一步自然是商务对接 本专栏是作为付呗的普通级商户,商户后台 使用付呗开发平台的支付API,接入到 ...
- Redis进阶教程—基础篇-叶向阳-专题视频课程
Redis进阶教程-基础篇-217人已学习 课程介绍 该系列教程涵盖了redis的方方面面,大亮点是实战经验分享总结.系列视频包含Redis基础篇.Redis提升篇.从零编写Redis ...
- 视频教程-Redis进阶教程—基础篇-NoSQL
Redis进阶教程-基础篇 雅座Java架构师,架构开发公司百万级订单支付平台 叶向阳 ¥49.00 立即订阅 扫码下载「CSDN程序员学院APP」,1000+技术好课免费看 APP订阅课程,领取优惠 ...
- python人生苦短_人生苦短,我用Python(教程基础篇)
人生苦短,我用Python(Python快速教程 - 基础篇) Life is short, you need Python 人生苦短,我用Python Python简介 本章将介绍Python的最基 ...
最新文章
- 如何在鼠标hover时改变标注的样式
- 在ElasticSearch之下(图解搜索的故事)
- 网络:HTTP报文格式
- Thread如何中断
- IPsec ***数据传输过程
- rsync同步工具学习笔记
- exchange系列(一)exchange2010邮件服务器的安装与规划
- MIT 最新 AI 医疗系统公布:“重症监护室干预” 与”电子医疗档案模型迁移“...
- 输电线路覆冰智能预测预警系统
- 重庆地区外卖店铺分析系统的设计与实现
- 25 | 业务安全体系:对比基础安全,业务安全有哪些不同?
- v-charts 如何更改文本颜色
- timed out waiting for to be synced
- 从Word中读取内容将word转换成txt
- Python 绘制圆柱体(3D图)
- 怎么下载老版本android,剪映旧版下载
- 【开源】一款PyQT+Pyserial开发的串口调试工具
- 【reactor模式】【proactor模式】
- python api调用百度ai平台_百度ai开放平台使用方法(附带详细案例步骤)
- 《Linux运维总结:内网服务器通过代理访问外网服务器(方法一)》