Bazel 快速入门与核心知识

Bazel 快速入门与核心知识

Bazel 简介

Bazel 是一款与 Make、Maven 和 Gradle 类似的开源构建和测试工具。 它使用人类可读的高级构建语言。Bazel 支持多种语言的项目 (C/C++, Java, Python, …),可为多个平台构建输出。Bazel 支持跨多个代码库和大量用户的大型代码库。

本文是作者结合 Bazel 官方文档以及一些其他博客总结的学习笔记,凝炼了个人认为最核心的一些 Bazel 知识。通过此文,希望能让大家不仅看懂并编译一个通过 Bazel 构建的项目,同时还能够使用 Bazel 对自己的项目完成构建。

使用 Bazel 的基本流程

如需使用 Bazel 构建或测试项目,您通常要执行以下操作:

  1. 设置 Bazel。下载并安装 Bazel。

  2. 设置项目工作区,这是 Bazel 在其中查找 build 输入和 BUILD 文件以及用于存储 build 输出的目录。

  3. 编写 BUILD 文件,告知 Bazel 要构建什么以及如何构建它。

    如需编写 BUILD 文件,您可以使用领域特定语言 Starlark 声明构建目标。(请查看此处的示例。)

    构建目标指定了一组 Bazel 将要构建的输入工件及其依赖项,Bazel 将用于构建它的构建规则,以及用于配置构建规则的选项。

    build 规则用于指定 Bazel 将使用的构建工具,例如编译器和链接器。Bazel 附带多条构建规则,这些规则涵盖受支持平台上以支持的语言显示的最常见工件类型。

  4. 通过命令行运行 Bazel。Bazel 会将您的输出内容放在工作区中。

Bazel 构建流程

运行构建或测试时,Bazel 会执行以下操作:

  1. 加载与目标相关的 BUILD 文件。
  2. 分析输入及其依赖项,应用指定的构建规则,并生成操作图表。
  3. 对输入执行构建操作,直到生成最终构建输出。

由于之前的所有构建工作都已缓存,因此 Bazel 可以识别并重复使用缓存的 artifacts,并且只会重新构建或重新测试发生更改的内容。为了进一步强制执行正确性,您可以设置 Bazel,以通过沙盒化的方式运行构建和测试,从而最大限度地减少偏差并最大限度地提高可重现性。

Bazel C++ demo

目录组织结构如下。下面尝试用 bazel 构建 stage3/main 中以 hello-world.cc 为入口的 hello-world 程序,该程序依赖于同路径下的 hello-greet 以及 stage3/lib 路径下的 hello-time

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
  1. stage3 目录下创建了名为 WORKSPACE 的空文件,标记了这是一个 bazel 的工作区

  2. stage3/mainstage3/lib 目录下创建名为 BUILD 的文件,用于指示 bazel 构建工作,一个拥有 BUILD 文件的目录就是一个包 (软件包)

    # lib/BUILD 文件# 定义了名为"hello-time"的一个目标(target),这个目标是cc_library规则(rule)的一个实例,cc_library规则定义的是构建C/C++库(library)的规则
    cc_library(name = "hello-time",# 构建此库目标所需的C/C++文件列表,路径相对于BUILD文件所处目录srcs = ["hello-time.cc"],# 描述此库目标的C/C++头文件列表,路径相对于BUILD文件所处目录hdrs = ["hello-time.h"],# 使用可见性属性让 lib/BUILD 中的 //lib:hello-time 目标对 main/BUILD 中的目标显式可见。这是因为,默认情况下,只有同一 BUILD 文件中的其他目标才会看到这些目标。visibility = ["//main:__pkg__"],
    )
    
    # main/BUILD 文件# 定义了名为"hello-greet"的一个目标(target),这个目标是cc_library规则(rule)的一个实例,cc_library规则定义的是构建C/C++库(library)的规则
    cc_library(name = "hello-greet",# 构建此库目标所需的C/C++文件列表,路径相对于BUILD文件所处目录srcs = ["hello-greet.cc"],# 描述此库目标的C/C++头文件列表,路径相对于BUILD文件所处目录hdrs = ["hello-greet.h"],
    )# 定义了名为"hello-world"的一个目标(target),这个目标是cc_binary规则(rule)的一个实例,cc_binary规则定义的是构建C/C++二进制程序(binary)的规则
    cc_binary(name = "hello-world",# 构建此二进制目标所需的C/C++文件列表,路径相对于BUILD文件所处目录srcs = ["hello-world.cc"],# 要链接到二进制目标的其他库的列表deps = [":hello-greet",  # 同一包下可省略包路径和//"//lib:hello-time",  # 不同包下必须严格按照 //包路径:目标名 的标签写法],
    )
    

    目标间的依赖关系如下:

    “hello-world”的依赖关系图显示了文件修改后依赖关系的变化。

  3. 执行构建:在 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 即可运行 hello-world 程序

Bazel 核心知识

工作区 (workspace)

  • 一个 Workspace 就可以认为就是一个独立的 C/C++ Project。譬如上面 cpp-tutorial 目录下分别由 stage1stage2stage3 三个项目,每个项目的根目录下有一个 WORKSPACE 文件(空的就行)。
  • Bazel 会将包含一个 WORKSPACEWORKSPACE.bazel 文件的目录识别为一个项目,每个项目之间互不干扰是完全独立的。
    • 可以同时包含 WORKSPACEWORKSPACE.bazel,此时 .bazel 那个优先级更高。
  • 一个 Workspace 里可以包含多个 Packages (包),每个 Package 中包含一组相关的源文件和一个 BUILD 文件。BUILD 文件指定可以从源代码构建哪些输出。例如,stage3 下就包含了两个 Package:mainlib
  • 工作区有时也叫代码库。

BUILD & 包

  • 软件包 (包) 指的是包含名为 BUILDBUILD.bazel 的 BUILD 文件的目录。

    • 可以同时包含 BUILDBUILD.bazel,此时 .bazel 那个优先级更高。
  • 软件包包含其目录中的所有文件,以及其下的所有子目录,但那些本身包含 BUILD 文件的子目录除外。根据此定义,任何文件或目录都不能包含在两个不同的软件包中。

    例如,以下目录树中有两个软件包:my/app 和子软件包 my/app/tests。请注意,my/app/data 不是软件包,而是属于软件包 my/app 的目录。

    src/
    └─ my└─ app├─ BUILD├─ app.cc├─ data│   └─ input.txt└─ tests├─ BUILD└─ test.cc
    
  • BUILD 文件采用 Starlark 语言对模块构建进行描述,语法类似于 Python

    • 每个 BUILD 文件都需要至少一条规则 (rule) 作为一组指令,告诉 Bazel 如何构建所需的输出,例如可执行文件或库。
    • BUILD 文件中定义的规则 (rule) 的实例都称为一个目标 (target),并指向一组特定的源文件和依赖项。 目标还可以指向其他目标。从逻辑上来说即每个 package 可以包含多个 targets,而具体的 target 则采用 Starlark 语法定义在一个 BUILD 文件中。

BUILD 文件核心语法

规则 (rule)
  • 规则用于在 BUILD 文件(例如 cc_library)中定义如何生成一个目标 (target)。从 BUILD 文件作者的角度来看,规则由一组属性和黑盒逻辑组成。

  • 在简单的 BUILD 文件中,规则声明可以随意重新排序,而不改变行为。

  • bazel 定义了很多原生规则,可以直接在 BUILD 文件中使用,而无需 load 语句引入

    • 可以在 .bzl 文件中自定义规则,并在 BUILD 中用 load 语句引入。

    • 原生规则可以在 .bzl 文件中需要使用 native 模块来引用(如 native.cc_binary),但在 BUILD 文件中原生规则可以直接使用。

    • 详细的各项原生规则及其API见文档:Bazel 构建函数百科全书 (google.cn)。

      在这里插入图片描述

    • 我们常用的原生规则包括 cc_binarycc_library 等,分别用来构建二进制可执行程序和库(静态库/动态库)。

      # 例子:在BUILD中使用bazel内置的原生规则: cc_binary
      cc_binary(name = "hello-world",srcs = ["hello-world.cc"],deps = [":hello-greet","//lib:hello-time",],
      )
      
  • 大多数规则都具有类似的命名方案。例如,cc_binarycc_librarycc_test 分别是 C++ 二进制文件、库和测试的构建规则。其他语言会采用相同的命名方案,但采用不同的前缀,例如适用于 Java 的 java_*

    • *_binary 规则可用于构建给定语言的可执行程序。
    • *_test 规则是 *_binary 规则的专用规则,用于自动测试。测试只是在成功时返回零的程序。
    • *_library 规则以指定给定的编程语言指定单独编译的模块。库可以依赖于其他库,二进制文件和测试可以依赖于库,并且具有预期的单独编译行为。
  • 一个规则一般具有很多属性(见后面的小节)。

目标 (target)
  • 规则和目标是定义和实现的关系。也就是说,目标是规则的一个实例

    • 一个 Rule 由很多 attribute 构成,这点采用面向对象的概念来看,Rule 就好比是 class,而 attribute 就好比是 class 的 member。

    • 下面这段代码实际上就是定义了一个 target,每个实例必须要有一个名字在同一个 package 中和其他 target 实例进行区分。所以 name 这个 attribute 是必须有的,其他 attribute 是可选的,不写则按默认值定义。

      # 例子:定义一个name为"hello-world"的target,它是cc_binary规则的一个实例 
      cc_binary(name = "hello-world",srcs = ["hello-world.cc"],deps = [":hello-greet","//lib:hello-time",],
      )
      
  • 可以使用标签来唯一标识一个目标(详下节)。

标签 (label)
  • 标签是目标的标识符。简单来说,标签就是唯一标识一个 target 的 ID

  • 大部分情况下,我们引用的都是同一个 workspace 中的 target,此时标签的语法如下

    //path/to/package:target-name
    
    • // 开始,接下来的 path/to/package 也就是这个 target 所在 package 在 workspace 中的相对路径。然后是一个 : 后面跟着一个 target-name 即上面说的一个 target 中的 name 那个属性的字符串值。

    • 如果要引用不同 workspace 中的 target,就必须使用标签的完整语法,见:标签 | Bazel (google.cn)

    • 如果是引用同一个包中的 target,那么标签语法可进一步简化,以下两种方式均可:

      //:target-name
      :target-name
      
  • 特别地,可以使用 //path/to/package:__pkg__ 来表示一个包下地所有 target。

属性 (attribute) 及依赖
  • 属性是规则的参数,用于表示每个目标的 build 信息。如果在 BUILD 中实例化规则时没有显式指定某个属性的值,则该属性会使用默认值。

  • 大多数规则常见的属性包括 names (必需)、srcsdepsdatavisibilityincludescopts等,它们分别声明目标的源文件、依赖项和自定义编译器选项。给定目标可用的特定属性取决于其规则类型。

  • 原生规则的具体属性需要参见文档:Bazel 构建函数百科全书 (google.cn)。以 cc_library 规则为例,说明它的一些常用属性:

    • names: 目标的唯一名称。
    • deps: 此库所依赖的其他库的列表(可以通过标签来引用)。
    • srcs: 为创建库目标而处理的 C 和 C++ 文件的列表,包括源文件和头文件
    • data: 此库在运行时所需的文件列表。
    • hdrs: 伴随此库发布的头文件,并且可以被其他依赖这个库的目标(如其他 cc_librarycc_binary)使用,Bazel 在构建过程中会确保这些头文件能够被正确找到和使用。cc_binary等规则是没有此属性的。
    • visibility: 指定此库在其他库中的可见性(可以通过标签来引用)。默认情况下,一个目标只对相同库中的其他目标显式可见。
    • includes: 要添加到编译行的 include 目录列表。
    • copts: 将这些选项添加到 C++ 编译命令中。比如这里可以写 -Imy_libpath 来将 my_libpath 加入编译时的头文件搜索路径,可以写 -pthread 来表明使用了多线程库。
      • includescopts 中设置 -I 都可以指定头文件位置。但是,前者会为该规则即依赖该规则的所有规则都设置头文件位置,而后者只会为该规则设置头文件位置(因为本身只是一次编译命令的选项)。

    注意到这里并没有指定生成 .a 静态库还是 .so 动态库,实际上静态库还是动态库由引用此库的 cc_binary 规则决定,具体来说,cc_binary 可以指定 linksharedlinkstatic 为 True 还是 False 来决定链接时使用动态库还是静态库。默认情况下,linkshared 是 False,linkstatic 是 True。

    此外需要说明的是,srcsdatahdrsincludes 等属性中设置的地址都是相对于当前包路径而言的,即相对于当前 BUILD 文件所处的目录

    以下给出一个示例:最终目标是构建可执行程序 foo,它依赖于源文件 foo.cc 和头文件 foo.h,同时还依赖于库 bar。库 bar 则依赖于源文件 bar.cc 和头文件 bar-impl.h,它同时还依赖于另一个库 baz,库 bar 中的接口由 bar.h 这个头文件所定义。另一个库 baz 依赖于源文件 baz.ccbaz-impl.h,库 baz 中的接口由 baz.h 这个头文件所定义。

    cc_binary(name = "foo",srcs = ["foo.cc","foo.h",],deps = [":bar"],
    )cc_library(name = "bar",srcs = ["bar.cc","bar-impl.h",],hdrs = ["bar.h"],deps = [":baz"],
    )cc_library(name = "baz",srcs = ["baz.cc","baz-impl.h",],hdrs = ["baz.h"],
    )
    
  • 在 srcs, deps 等依赖属性中,可以使用 bazel 提供的 glob 函数来查找与特定路径模式匹配的所有文件,详细语法见:glob

构建命令

详细的各项参数见:使用 Bazel 构建程序 (google.cn)

使用 bazel build 来完成对目标的构建:

# 以 // 开头的所有目标模式都是相对于当前工作区而言的。
bazel build //path/to/package:target-name# 以 // 开头的目标模式会根据当前的工作目录进行解析。
bazel build path/to/package:target-name

案例:

# 构建workspace下的foo/bar包中的wiz目标
bazel build //foo/bar:wiz# 构建workspace下的foo/bar包中的bar目标,等同于 //foo/bar:bar
bazel build //foo/bar# 构建workspace下的foo/bar包中的全部目标
bazel build //foo/bar:all# 构建当前目录下定义的foo目标
bazel build :foo# 构建当前目录下的bar子目录下定义的foo目标
bazel build bar:wiz

参考文献

  • Google Bazel 官方教程
  • bazel工程介绍和demo构建_bazel构建方式图-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/413464.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ncnn之yolov5(7.0版本)目标检测pnnx部署

一、pnxx介绍与使用 pnnx安装与使用参考: https://github.com/pnnx/pnnxhttps://github.com/Tencent/ncnn/wiki/use-ncnn-with-pytorch-or-onnxhttps://github.com/Tencent/ncnn/tree/master/tools/pnnx 支持python的首选pip,否则就源码编译。 pip3 …

opencv/c++的一些简单的操作(入门)

目录 读取图片 读取视频 读取摄像头 图像处理 腐蚀 膨胀 调整图像大小 裁剪和缩放 绘制 绘制矩形 绘制圆形 绘制线条 透视变换 颜色检测 轮廓查找 人脸检测 检测人脸 检测嘴巴 可适当调整参数 读取图片 读取路径widows使用vis sto一定是\斜杠 #include <o…

界面控件Telerik UI for ASP.NET Core 2024 Q2亮点 - AI与UI的融合

Telerik UI for ASP.NET Core是用于跨平台响应式Web和云开发的最完整的UI工具集&#xff0c;拥有超过60个由Kendo UI支持的ASP.NET核心组件。它的响应式和自适应的HTML5网格&#xff0c;提供从过滤、排序数据到分页和分层数据分组等100多项高级功能。 本文将介绍界面组件Teler…

【服务对接】✈️SpringBoot 项目整合华为云 obs 对象存储服务

目录 &#x1f44b;前言 &#x1f440;一、环境准备 &#x1f331;二、整合实现 1.依赖引入 2.准备 AK 和 SK ​ 3.配置类 4.obs 工具类封装 &#x1f49e;️三、测试使用 &#x1f37b;四、 obs 客户端 &#x1f4eb;五、章末 &#x1f44b;前言 小伙伴们大家好&…

Oracle查询优化--分区表建立/普通表转分区表

本文介绍了Oracle表分区的方法&#xff0c;将已有的非分区表转化为分区表&#xff0c;也可以直接建立新的分区表&#xff0c;从而实现大表查询的优化。主要通过DBMS_REDEFINITION 和 alter table xxx modify 方法&#xff0c;DBMS_REDEFINITION 适用于所有版本&#xff0c;操作…

计算机毕业设计选题推荐-大学生竞赛管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

【C++ 第十六章】哈希

1. unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到 &#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中的节点非常多时&#xff0c;查询效率也不理想。最好 的查询是&#xff0c;进行…

基于爬山法MPPT和PI的直驱式永磁同步风力发电机控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 PMSM 4.2 MPPT 4.3 PI 控制器原理 5.完整工程文件 1.课题概述 基于爬山法最大功率点跟踪 (Maximum Power Point Tracking, MPPT) 和比例积分控制器 (Proportional Integral, PI) 的直驱式永磁同步…

两个月冲刺软考——关系模式中的候选关键字与如何分解为无损连接并保持函数依赖的解法(例题讲解,看完必会)

1. 数据库中的简单属性、多值属性、复合属性、派生属性 简单属性&#xff1a;指不能够再分解成更小部分的属性&#xff0c;通常是数据表中的一个列。例如学生表中的“学号”、“姓名”等均为简单属性。 多值属性&#xff1a;指一个属性可以有多个值。例如一个学生可能会有多个…

栈OJ题——有效的括号

文章目录 一、题目链接二、解题思路三、解题代码 一、题目链接 有效的括号 题目描述&#xff1a;给定一个只包括 ‘(’&#xff0c;‘)’&#xff0c;‘{’&#xff0c;‘}’&#xff0c;‘[’&#xff0c;‘]’ 的字符串 s &#xff0c;判断字符串是否有效。括号匹配。 二、…

异业联盟的巅峰之作!某店生活 两年百亿销售额!

大家好 我是一家软件开发公司的产品经理 吴军 最近有个爆火的商业模式 带动了三方消费 平台能赚到钱 消费者能省钱 商家也能获取到客源甚至还能赚钱 他究竟是怎么样做到三方都赚到钱的&#xff1f; 在当前经济形势下&#xff0c;许多消费者变得谨慎&#xff0c;减少了不必…

100天带你精通Python——第8天面向对象编程

文章目录 前言面向对象技术简介类&#xff08;Class&#xff09;对象&#xff08;Object&#xff09;继承&#xff08;Inheritance&#xff09;封装&#xff08;Encapsulation&#xff09;多态&#xff08;Polymorphism&#xff09;Python类详解静态变量&#xff08;Static Var…

day39(8/29)——harbor私有仓库管理

一、harbor私有仓库管理 是python的包管理工具&#xff0c;和yum对redhat的关系是一样的 yum -y install epel-release yum -y install python2-pip pip install --upgrade pip pip list pip 8x pip install --upgrade pip pip install --upgrade pip20.3 -i https://mirror…

应用层(Web与HTTP)

目录 常见术语 1.HTTP概况 2.HTTP连接 非持久HTTP流程 响应时间模型 持久HTTP 3.HTTP报文 3.1HTTP请求报文 3.2HTTP响应报文 HTTP响应状态码 4.Cookies&#xff08;用户-服务器状态&#xff09; cookies&#xff1a;维护状态 Cookies的作用 5.Web缓冲&#xff08;…

yolo格式数据集|自动驾驶|5类别|数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用

本数据为自动驾驶检测数据集&#xff0c;数据集是车类摄像头在不同场景下拍摄&#xff0c;有5类&#xff0c;分别为car、truck、person、bicycle、traffic_light。数据集整理不易&#xff0c;获取地址在最后。 数据集数量如下&#xff1a; 总共有:18000张 训练集&#xff1a;14…

【卷起来】VUE3.0教程-01-环境搭建与安装

​分享不易&#xff0c;耗时耗力&#xff0c;麻烦给个不要钱的关注和赞吧 &#x1f332; 什么是VUE Vue 是一个框架&#xff0c;也是一个生态。其功能覆盖了大部分前端开发常见的需求。但 Web 世界是十分多样化的&#xff0c;不同的开发者在 Web 上构建的东西可能在形式和规模…

算法-最长连续序列

leetcode的题目链接 这道题的思路主要是要求在O&#xff08;n)的时间复杂度下&#xff0c;所以你暴力解决肯定不行&#xff0c;暴力至少两层for循环&#xff0c;所以要在O&#xff08;n)的时间复杂度下&#xff0c;你可以使用HashSet来存储数组&#xff0c;对于每个数字&#…

给鼠标一个好看的指针特效 鼠标光标如何修改形状?

许多爱美的小伙伴们都想着如何给自己的电脑打扮一下&#xff0c;用各种各样的途径来美化我们的电脑。今天我们给大家分享一下&#xff0c;如何美化鼠标效果&#xff0c;给鼠标指针修改成一个非常好看的形状~ 一起来看几组鼠标的效果&#xff0c;小编我给大家做了个录屏&#x…

YoloV8实战:使用YoloV8实现OBB框检测

定向边框(OBB)数据集概述 使用定向边界框(OBB)训练精确的物体检测模型需要一个全面的数据集。本文解释了与Ultralytics YOLO 模型兼容的各种 OBB 数据集格式,深入介绍了这些格式的结构、应用和格式转换方法。数据集使用DOTA。 YOLO支持的 OBB 格式 在Ultralytics YOLO …

AI编码新时代:免费人工智能助手Blackbox AI

前言&#xff1a; 在当今快速发展的科技时代&#xff0c;人工智能已经渗透到我们生活的方方面面&#xff0c;从智能手机的语音助手到智能家居控制系统&#xff0c;再到在线客服和个性化推荐算法&#xff0c;AI智能工具正变得越来越普遍。它们以其高效、智能和用户友好的特性&am…