热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Bazel简介:构建C++项目

官方地址:https:docs.bazel.buildversionsmastertutorialcpp.html#specify-multiple-build-targets在本

官方地址:https://docs.bazel.build/versions/master/tutorial/cpp.html#specify-multiple-build-targets

 

 在本教程中,您将学习使用Bazel构建C ++应用程序的基础知识。您将设置工作区构建一个简单的C ++项目,该项目演示了关键的Bazel概念,例如目标和BUILD文件。完成本教程后,请查看 Common C ++ Build Use Cases,了解更高级概念的信息,例如编写和运行C ++测试。

预计完成时间:30分钟。

 


你会学到什么

在本教程中,您将学习如何:

  • 建立目标
  • 可视化项目的依赖项
  • 将项目拆分为多个目标和包
  • 跨包控制目标可见性
  • 通过标签引用目标

内容


  • 你会学到什么
  • 在你开始之前
  • 用Bazel构建
    • 设置工作区
    • 理解BUILD文件
    • 建立项目
    • 查看依赖关系图
  • 优化您的Bazel构建
    • 指定多个构建目标
    • 使用多个包
  • 使用标签来引用目标
  • 进一步阅读

 


在你开始之前

要准备本教程,请先安装Bazel,如果尚未安装它。然后,从Bazel的GitHub存储库中检索示例项目:

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

 

本教程的示例项目位于examples/cpp-tutorial目录中,结构如下:

└── 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

如您所见,有三组文件,每组代表本教程中的一个阶段。

第一阶段,您将构建一个驻留在单个包中的目标

在第二阶段,您将项目拆分为多个目标,但将其保存在单个包中。

在第三个也是最后一个阶段,您将项目拆分为多个包,并使用多个目标构建它

 


用Bazel构建


设置工作区

在构建项目之前,需要设置其工作区工作空间保存项目源文件 和 Bazel构建输出的目录。它还包含Bazel认为特殊的文件:

  • WORKSPACE文件将目录及其内容标识为Bazel工作区,并且位于项目目录结构的根目录下,

  • 一个或多个BUILD文件,告诉Bazel如何构建项目的不同部分。(工作空间中包含BUILD文件的目录是一个。您将在本教程后面学习包。)

要将目录指定为Bazel工作空间,请创建WORKSPACE在该目录中命名的空文件 。

当Bazel构建项目时,所有输入依赖项必须位于同一工作区中除非链接,否则驻留在不同工作空间中的文件彼此独立,这超出了本教程的范围。

 

 

理解BUILD文件

  一个BUILD文件包含Bazel几种不同类型的指令。最重要的类型是构建规则,它告诉Bazel如何构建所需的输出,例如可执行的二进制文件或库。

文件中的每个构建规则实例BUILD都称为目标,并指向一组特定的源文件和依赖项。目标也可以指向其他目标。

看一下目录BUILD中的cpp-tutorial/stage1/main文件:

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

在我们的示例中,hello-world目标实例化Bazel的内置 cc_binary规则。该规则告诉Bazel从hello-world.cc源文件构建一个自包含的可执行二进制文件,没有依赖项。

目标中的属性显式声明其依赖项和选项。虽然该name属性是必需的,但许多属性是可选的。例如,在 hello-world目标中,name是不言自明的,并srcs指定Bazel构建目标的源文件。

 


建立项目

让我们构建您的示例项目。切换到cpp-tutorial/stage1目录并运行以下命令:

bazel build //main:hello-world

注意目标标签 - 该//main:部分是我们BUILD 文件相对于工作空间根的位置,

hello-world是我们在BUILD文件中命名该目标的位置。(您将在本教程末尾更详细地了解目标标签。)

 

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目标!Bazel将构建输出放在bazel-bin工作区根目录的目录中。浏览其内容以了解Bazel的输出结构。

现在测试新构建二进制文件:

bazel-bin/main/hello-world


 


 


查看依赖关系图

 成功构建的所有依赖项都在BUILD 文件中明确说明。Bazel使用这些语句来创建项目的依赖图,从而实现准确的增量构建。

让我们可视化我们的示例项目的依赖项。首先,生成依赖图的文本表示(在工作区根目录下运行命令):

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

 

 上面的命令告诉Bazel查找目标的所有依赖项 //main:hello-world(不包括主机和隐式依赖项),并将输出格式化为图形。

然后,将文本粘贴到GraphViz中。

在Ubuntu上,您可以通过安装GraphViz和xdot Dot Viewer在本地查看图形:

sudo apt update && sudo apt install graphviz xdot

然后,您可以通过将上面的文本输出直接管道到xdot来生成和查看图形:

xdot <(bazel query --nohost_deps --noimplicit_deps &#39;deps(//main:hello-world)&#39; \--output graph)

如您所见&#xff0c;示例项目的第一个阶段有一个目标&#xff0c;它构建一个没有其他依赖项的源文件&#xff1a;

&#39;hello-world&#39;的依赖关系图

现在您已经设置了工作区&#xff0c;构建了项目并检查了它的依赖项&#xff0c;让我们添加一些复杂性。

 

 

优化您的Bazel构建

虽然单个目标足以满足小型项目的需要&#xff0c;但您可能希望将较大的项目拆分为多个目标和程序包以允许快速增量构建&#xff08;即&#xff0c;仅重建已更改的内容&#xff09;并通过构建项目的多个部分来加速构建立刻。

指定多个构建目标

让我们将示例项目构建拆分两个目标。看一下 目录BUILD中的cpp-tutorial/stage2/main文件&#xff1a;

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

使用此BUILD文件&#xff0c;Bazel首先构建hello-greet库&#xff08;使用Bazel的内置cc_library规则&#xff0c;然后是hello-world二进制文件。目标中的deps属性hello-world告诉Bazel hello-greet需要库来构建hello-world 二进制文件。

让我们构建这个项目的新版本。切换到 cpp-tutorial/stage2目录并运行以下命令&#xff1a;

bazel build //main:hello-world

 

Bazel产生的输出类似于以下内容&#xff1a;

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

 

现在测试新构建的二进制文件&#xff1a;

bazel-bin/main/hello-world

 

如果您现在修改hello-greet.cc并重建项目&#xff0c;Bazel将只重新编译该文件。

查看依赖关系图&#xff0c;您可以看到它hello-world依赖于之前相同的输入&#xff0c;但构建的结构是不同的&#xff1a;

&#39;hello-world&#39;的依赖关系图

您现在已经使用两个目标构建了项目。的hello-world目标建立一个源文件&#xff0c;并取决于一个其他目标&#xff08;//main:hello-greet&#xff09;&#xff0c;它建立两个附加的源文件。

 


使用多个包

现在让我们将项目拆分多个包。看一下cpp-tutorial/stage3目录的内容&#xff1a;

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

请注意&#xff0c;我们现在有两个子目录&#xff0c;每个子目录都包含一个BUILD文件。因此&#xff0c;对于Bazel&#xff0c;工作区现在包含两个包&#xff0c;lib并且main

看看lib/BUILD文件&#xff1a;

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

 

并在main/BUILD文件中&#xff1a;

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

 

正如你所看到的&#xff0c;hello-world在目标main包依赖于 hello-time目标lib包&#xff08;因此目标标签 //lib:hello-time&#xff09; -巴泽尔通过知道这个deps属性。看一下依赖图&#xff1a;

&#39;hello-world&#39;的依赖关系图

请注意&#xff0c;为了使构建成功&#xff0c;我们使用该 属性使//lib:hello-time目标 lib/BUILD明确显示给目标。这是因为默认目标仅对同一文件中的其他目标可见。&#xff08;Bazel使用目标可见性来防止诸如包含实现细节的库泄漏到公共API中的问题。&#xff09;main/BUILDvisibilityBUILD

 

让我们构建我们项目的最终版本。切换到 cpp-tutorial/stage3目录并运行以下命令&#xff1a;

bazel build //main:hello-world

 

Bazel产生的输出类似于以下内容&#xff1a;

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

 

现在测试新构建的二进制文件&#xff1a;

bazel-bin/main/hello-world

您现在已经将项目构建为具有三个目标的两个包&#xff0c;并了解它们之间的依赖关系。

 


 


使用标签来引用目标

BUILD文件和命令行中&#xff0c;Bazel使用标签引用目标 - 例如&#xff0c;//main:hello-world//lib:hello-time。他们的语法是&#xff1a;

//path/to/package:target-name

如果目标是规则目标&#xff0c;那么path/to/package是包含该BUILD文件的目录的路径&#xff0c;并且target-name是您在BUILD文件中命名目标的&#xff08;name属性&#xff09;。如果目标是文件目标&#xff0c;则path/to/package是包的根目录的路径&#xff0c;并且 target-name是目标文件的名称&#xff0c;包括其完整路径。

在同一个包中引用目标时&#xff0c;可以跳过包路径并使用//:target-name。在同一BUILD 文件中引用目标时&#xff0c;您甚至可以跳过//工作区根标识符并使​​用 :target-name

进一步阅读

恭喜&#xff01;您现在已经了解了使用Bazel构建C &#43;&#43;项目的基础知识。接下来&#xff0c;阅读最常见的C &#43;&#43;构建用例。然后&#xff0c;查看以下内容&#xff1a;

  • 外部依赖关系&#xff0c;以了解有关使用本地和远程存储库的更多信息。

  • 在构建百科全书了解更多关于巴泽尔。

  • 在Java构建教程上手与巴泽尔构建Java应用程序。

  • 该Android应用教程上手构建移动应用程序为Android与巴泽尔。

  • 在iOS版应用教程上手构建移动应用程序与巴泽尔的iOS。

快乐的建筑&#xff01;

 

希望对你有帮助。


推荐阅读
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 安装mysqlclient失败解决办法
    本文介绍了在MAC系统中,使用django使用mysql数据库报错的解决办法。通过源码安装mysqlclient或将mysql_config添加到系统环境变量中,可以解决安装mysqlclient失败的问题。同时,还介绍了查看mysql安装路径和使配置文件生效的方法。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • Commit1ced2a7433ea8937a1b260ea65d708f32ca7c95eintroduceda+Clonetraitboundtom ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Ubuntu安装常用软件详细步骤
    目录1.GoogleChrome浏览器2.搜狗拼音输入法3.Pycharm4.Clion5.其他软件1.GoogleChrome浏览器通过直接下载安装GoogleChro ... [详细]
author-avatar
手机用户2502933795
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有