文章目录

  • Bazel入门教程:编译C++项目
    • 安装bazel
    • 编译C++项目
      • 建立工作区(workspace)
      • 理解BUILD文件
      • 使用Bazel编译项目
        • 1. 编译你的第一个Bazel项目
        • 2. 查看依赖图
        • 3.多个target的编译
        • 4. 多个package的编译

Bazel入门教程:编译C++项目

安装bazel

参见我的博客:https://blog.csdn.net/weixin_44493841/article/details/105951633

编译C++项目

建立工作区(workspace)

Bazel的编译是基于工作区(workspace)的概念。工作区是一个存放了所有源代码和Bazel编译输出文件的目录,也就是整个项目的根目录。同时它也包含一些Bazel认识的文件:
WORKSPACE文件,用于指定当前文件夹就是一个Bazel的工作区。所以WORKSPACE文件总是存在于项目的根目录下。
一个或多个BUILD文件,用于告诉Bazel怎么构建项目的不同部分。(如果工作区中的一个目录包含BUILD文件,那么它就是一个package。)
那么要指定一个目录为Bazel的工作区,就只要在该目录下创建一个空的WORKSPACE文件即可。
当Bazel编译项目时,所有的输入和依赖项都必须在同一个工作区。属于不同工作区的文件,除非linked否则彼此独立。

理解BUILD文件

一个BUILD文件包含了几种不同类型的指令。其中最重要的是编译指令,它告诉Bazel如何编译想要的输出,比如可执行二进制文件或库。BUILD文件中的每一条编译指令被称为一个target,它指向一系列的源文件和依赖,一个target也可以指向别的target。
举个例子,下面这个hello-world的target利用了Bazel内置的cc_binary编译指令,来从hello-world.cc源文件(没有其他依赖项)构建一个可执行二进制文件。指令里面有些属性是强制的,比如name,有些属性则是可选的,srcs表示的是源文件。

cc_binary(name = "hello-world",srcs = ["hello-world.cc"],
)

使用Bazel编译项目

Bazel提供了一些编译的例子,在https://github.com/bazelbuild/examples/,可以clone到本地试一下。

git clone https://github.com/bazelbuild/examples/ ./examples

其中examples/cpp-tutorial目录下包含了这么些文件:

examples
└── cpp-tutorial├──stage1│  └── main│      ├── BUILD│      ├── hello-world.cc│  └── WORKSPACE├──stage2│  ├── main│  │   ├── BUILD│  │   ├── hello-world.cc│  │   ├── hello-greet.cc│  │   ├── hello-greet.h│  └── WORKSPACE└──stage3├── main│   ├── BUILD│   ├── hello-world.cc│   ├── hello-greet.cc│   └── hello-greet.h├── lib│   ├── BUILD│   ├── hello-time.cc│   └── hello-time.h└── WORKSPACE

可以看到分成了3组文件,分别对应本文中的3个例子。在第一个例子中,我们首先学习如何构建单个package中的单个target。在第二个例子中,我们将把整个项目拆分成单个package的多个target。第三个例子则将项目拆分成多个package,用多个target编译。

1. 编译你的第一个Bazel项目

首先进入到cpp-tutorial/stage1目录下(注意:目录中不能有中文,bazel不认识中文,会编译报错),然后运行以下指令:

bazel build //main:hello-world

注意target中的//main:是BUILD文件相对于WORKSPACE文件的位置,hello-world则是我们在BUILD文件中命名好的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 target就编译好了!Bazel将编译的输出放在项目根目录下的bazel-bin目录下,可以看一下这个目录,理解一下Bazel的输出结构。
现在你可以测试你刚刚生成的二进制文件了:

bazel-bin/main/hello-world

2. 查看依赖图

一个成功的build将所有的依赖都显式定义在了BUILD文件中。Bazel使用这些定义来创建项目的依赖图,这能够加速编译的过程。
让我们来可视化一下我们项目的依赖吧。首先,生成依赖图的一段文字描述(即在工作区根目录下运行下述指令):

bazel query --nohost_deps --noimplicit_deps 'deps(//main:hello-world)' \--output graph

这个指令告诉Bazel查找target //main:hello-world的所有依赖项(不包括host和隐式依赖),然后输出图的文字描述。再把文字描述贴到GraphViz里,你就可以看到如下的依赖图了。可以看出这个项目是用单个源文件编译出的单个target,并没有别的依赖。

好的,到目前为止,我们已经建立了工作区,编译了一个项目,并且查看了它的依赖。接下来让我们加点难度。

3.多个target的编译

单个target的方式对于小项目来说是高效的,但是对于大项目来说,你可能会想把它拆分成多个target和多个package来实现快速增量的编译(这样就只需要重新编译改变过的部分)。
首先我们来尝试着把项目拆分成两个target。看一下cpp-tutorial/stage2/main目录下的BUILD文件,它是这样的:

cc_library(name = "hello-greet",srcs = ["hello-greet.cc"],hdrs = ["hello-greet.h"],
)
cc_binary(name = "hello-world",srcs = ["hello-world.cc"],deps = [":hello-greet",],
)

我们看到在这个BUILD文件中,Bazel首先编译了hello-greet这个库(利用Bazel内置的cc_library编译指令),然后编译hello-world这个二进制文件。hello-world这个target的deps属性告诉Bazel,要构建hello-world这个二进制文件需要hello-greet这个库。
好,让我们编译一下新的版本。进入到cpp-tutorial/stage2目录下然后运行以下指令:

bazel build //main:hello-world

然后Bazel又会有一些类似这样的输出:

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然后重新编译整个项目的话,Bazel其实只会编译修改过的那个文件。
然后我们再来看一下依赖图,发现hello-world在编译时候的结构和之前有所不同,现在是有两个targets。hello-world这个target从一个源文件编译而来,同时依赖于另一个target//main:hello-greet,这个target又是从两个源文件编译而来。

4. 多个package的编译

我们现在再将项目拆分成多个package。看一下cpp-tutorial/stage3目录下的内容:

└──stage3├── main│   ├── BUILD│   ├── hello-world.cc│   ├── hello-greet.cc│   └── hello-greet.h├── lib│   ├── BUILD│   ├── hello-time.cc│   └── hello-time.h└── WORKSPACE

注意到我们现在有两个子目录了,每个子目录中都包含了BUILD文件。因此,对于Bazel来说,整个工作区现在就包含了两个package:libmain
lib/BUILD文件长这样:

cc_library(name = "hello-time",srcs = ["hello-time.cc"],hdrs = ["hello-time.h"],visibility = ["//main:__pkg__"],
)

main/BUILD文件长这样:

cc_library(name = "hello-greet",srcs = ["hello-greet.cc"],hdrs = ["hello-greet.h"],
)
cc_binary(name = "hello-world",srcs = ["hello-world.cc"],deps = [":hello-greet","//lib:hello-time",],
)

可以看出hello-world这个mainpackage中的target依赖于lib package中的hello-time target(即target label为://lib:hello-time)- Bazel是通过deps这个属性知道自己的依赖项的。那么现在依赖图就变成了下图的样子:
注意到lib/BUILD文件中我们将hello-time这个target显式可见了(通过visibility属性)。这是因为默认情况下,targets只对同一个BUILD文件里的其他targets可见(Bazel使用target visibility来防止像公有API中库的实现细节的泄露等情况)。
好,让我们编译一下新的版本。进入到cpp-tutorial/stage3目录下然后运行以下指令:

bazel build //main:hello-world

然后Bazel又会有一些类似这样的输出:

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

好,现在我们学会了编译一个包含2个package和3个target的项目,并且理解了它们之前的依赖关系。

Bazel入门教程:编译C++项目相关推荐

  1. TensorFlow 中文资源精选,官方网站,安装教程,入门教程,实战项目,学习路径。

    转载至:http://www.nanjixiong.com/thread-122211-1-1.html Awesome-TensorFlow-Chinese TensorFlow 中文资源全集,学习 ...

  2. [carla入门教程]-6 小项目:基于carla-ros-bridge构建一个小型比赛赛道

    本专栏教程将记录从安装carla到调用carla的pythonAPI进行车辆操控并采集数据的全流程,带领大家从安装carla开始,到最终能够熟练使用carla仿真环境进行传感器数据采集和车辆控制. 第 ...

  3. [github 教程]手把手教你最简单的开源项目托管GitHub入门教程_github 教程

    [github 教程]手把手教你最简单的开源项目托管GitHub入门教程--简介 自从google code关闭了下载服务了之后,GitHub作为了目前最好用的免费 开源 项目托管站点,众多开源项目都 ...

  4. ASP.NET MVC 5 入门教程 (2) 控制器Controller

    原文:ASP.NET MVC 5 入门教程 (2) 控制器Controller 文章来源: Slark.NET-博客园 http://www.cnblogs.com/slark/p/mvc-5-get ...

  5. ros2与windows入门教程-windows上安装ROS2 foxy

    系列文章目录 ros2与windows入门教程-windows上安装ROS2 foxy ros2与windows入门教程-控制小乌龟 ros2与windows入门教程-监听和发布话题 ros2与win ...

  6. 推荐10个适合初学者的 HTML5 入门教程

    HTML5 作为下一代网站开发技术,无论你是一个 Web 开发人员或者想探索新的平台的游戏开发者,都值得去研究.借助尖端功能,技术和 API,HTML5 允许你创建响应性.创新性.互动性以及令人惊叹的 ...

  7. C#,入门教程(06)——解决方案资源管理器,代码文件与文件夹的管理工具

    上一篇: C#,入门教程(05)--Visual Studio 2022源程序(源代码)自动排版的功能动画图示https://blog.csdn.net/beijinghorn/article/det ...

  8. ESP32-C3入门教程 环境篇⑥——ESP-IDF编译原理简述(CMakeLists/CMake)和构建自定义项目

    文章目录 一.前言 二.ESP-IDF编译原理 2.1 基础知识 2.2 软件组件 2.3 构建过程 2.4 最简单的示例项目 三.构建自定义项目 3.1 项目重命名 3.2 main.c重命名 3. ...

  9. Egg框架入门教程合集之插件/工具/教程/专栏/开源项目

    Egg框架入门教程之示例合集 Awesome Egg.js 很棒的清单,精选了最好的Egg.js插件,工具,教程,文章等.欢迎公关! 内容 博客 文章 讲解 会议活动 外挂程式 应用领域 样板 构架 ...

最新文章

  1. 陈长沙:学习者参考手册
  2. mysql 计算两个日期之间的天数
  3. android自定义LinearLayout和View
  4. 笔记-项目干系人管理-管理干系人参与
  5. awesome-go:很全的go语言资源合集
  6. oracle数据库安装过程中出现主目录不兼容的问题
  7. 循序渐进:Oracle 12c新特性Sharding技术解读
  8. 人本原理内涵_叶澜教育学原理课后答案资料配套题库考研真题精选课后习题章节题库...
  9. java 显示图片的一部分_求只显示图片上半部分三分之一的写法
  10. python模型预测结果 取整_一日一技:Python里面的//并不是做了除法以后取整
  11. Hive编程指南(含目录,高清,免费)
  12. EL表达式和JSTL标签
  13. 每台计算机需要配置网关吗,怎么设置一台电脑作为网关
  14. 爬虫爬取taptap上关于厂商的评论
  15. Windows下如何对声卡音频输出进行录音
  16. ECCV2022 | 网易AI 基于单幅图片的实时高分辨率人脸重演算法
  17. 给五子棋加个功能叫悔棋
  18. C# WinForm开发系列 - Open-Source Controls
  19. python爬虫案例分析:爬取肯德基门店地址数据导入csv文件并最终用excel文档呈现
  20. 刚学编程的程序员必备这5大编程网站,你知道几个? 1

热门文章

  1. ‘Link‘ is not exported from ‘react-router‘
  2. 字符串的模式匹配,KMP算法
  3. php中创建关联数组,以及遍历数组
  4. Nature | 有机合成的数字化
  5. Linux下编译运行C程序
  6. html5 上传超大文件,HTML5教程 如何拖拽上传大文件
  7. spring cloud 日志_微服务架构开发实战:ElasticStack实现日志集中化
  8. 零基础入门学习Python(17)-函数的参数
  9. 最后两天-微生物组-宏基因组分析(线上/线下同时开课,2020最后一期)
  10. Microbiome: 绝对定量环境样本细菌、真菌、真核群落丰度