什么是bazel

Bazel 是一款与 Make、Maven 和 Gradle 类似的开源构建和测验工具。 它运用人类可读懂的高档 build 言语。Bazel 支撑运用多种言语的项目,并针对多个渠道构建输出。Bazel 支撑跨多个代码库和很多用户的很多代码库。

Bazel的基本概念

WORKSPACE file

在构建项目之前,咱们需求先设置作业区,作业区的作用是存储项目的源文件和Bazel的构建输出的目录,其间WORKSPACE file便是将目录及其内容标识为Bazel作业区的文件,需求坐落项目目录结构的根目录下,该文件可认为空,但是通常包括从网络或者本地文件体系中提取其他依靠项的外部代码库声明。

BUILD file

一个项目中包括一个或多个BUILD file,BUILD首要用于奉告Bazel怎么构建项目,作业区包括一个BUILD文件的目录便是一个软件包。在之前的文章提到过,Bazel是基于工件的构建体系,而工件就能够理解为Bazel根据Build文件中的编译规矩编译该目录下的文件构成的,软件包能够包括子软件包或包括BUILD文件的子目录,从而构成软件包的层次。

BUILD文件中包括了一些适用于Bazel的不同类型的指令,每个BUILD文件都需求包括至少一条规矩(如cc_library)作为一组指令,以指示Bazel怎么构建所需求的输出,例如可执行文件或库。BUILD文件中的每一个build规矩实例都称为方针,并指向一组特定的源文件和依靠项,一个方针也能够指向其他方针。以下便是一个简略的BUILD文件的比如。

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

在本示例中,hello-world 方针会实例化 Bazel 的内置 cc_binary rule。该规矩会奉告 Bazel 从 hello-world.cc 源文件构建不含依靠项的独立可执行文件。

Bazel的C++事例

该比如是Bazel官方提供的,github地址为git clone github.com/bazelbuild/…

单个方针,单个软件包

咱们从最简略的比如开端,比如只包括一个源文件,需求将改源文件构建成一个可执行文件,其文件目录如下。

examples
└── cpp-tutorial
    └──stage1
       ├── main
       │   ├── BUILD
       │   └── hello-world.cc
       └── WORKSPACE

BUILD文件内容如下

load("@rules_cc//cc:defs.bzl", "cc_binary")
cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
)

然后进入该目录cpp-tutorial/stage1,运行以下命令构建

bazel build //main:hello-world

会打印以下信息表示编译成功

Starting local Bazel server and connecting to it...
INFO: Analyzed target //main:hello-world (37 packages loaded, 255 targets configured).
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 28.089s, Critical Path: 2.78s
INFO: 6 processes: 4 internal, 2 darwin-sandbox.
INFO: Build completed successfully, 6 total actions

然后能够运用以下命令测验,会打印Hello world

bazel-bin/main/hello-world

其依靠关系如下

单个软件包,多个方针

尽管单个方针足以满足小型项目的需求,在实践的开发过程中或许需求将较大的项目拆分为多个方针和软件包。这样能够完成快速增量构建(即 Bazel 仅重建更改的内容,并经过一次性构建项目的多个部分来加速构建速度。在教程的这一阶段,您将添加方针,然后添加软件包。

下面的BUILD文件会告知Bazel先构建hello-greet库(运用Bazel内置的cc_library)然后构建hello-world二进制文件,其间的deps特点告知Bazel构建hello-world需求hello-greet库。

load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
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",
    ],
)

编译状况如下

INFO: Analyzed target //main:hello-world (36 packages loaded, 258 targets configured).
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 15.548s, Critical Path: 2.39s
INFO: 8 processes: 4 internal, 4 darwin-sandbox.
INFO: Build completed successfully, 8 total actions

如果现在修正 hello-greet.cc 并重新构建项目,Bazel 只会重新编译该文件,编译结果如下(经过-s选项能够打印具体编译过程)

INFO: Analyzed target //main:hello-world (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
SUBCOMMAND: # //main:hello-greet [action 'Compiling main/hello-greet.cc', configuration: a42135a42aad3da7e3af209ce54745fb0d0306dc29e1f3dc84d7d58372421fc9, execution platform: @local_config_platform//:host]
(cd /private/var/tmp/_bazel_qiming/e4d33fbb5ee1f924b3cb079f19abf4eb/execroot/__main__ && \
  exec env - \
    APPLE_SDK_PLATFORM=MacOSX \
    APPLE_SDK_VERSION_OVERRIDE=13.1 \
    PATH=/Users/qiming/Library/Caches/bazelisk/downloads/bazelbuild/bazel-6.0.0-darwin-x86_64/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin \
    XCODE_VERSION_OVERRIDE=14.2.0.14C18 \
    ZERO_AR_DATE=1 \
  external/local_config_cc/wrapped_clang_pp '-D_FORTIFY_SOURCE=1' -fstack-protector -fcolor-diagnostics -Wall -Wthread-safety -Wself-assign -fno-omit-frame-pointer -O0 -DDEBUG '-std=c++11' 'DEBUG_PREFIX_MAP_PWD=.' -iquote . -iquote bazel-out/darwin-fastbuild/bin -MD -MF bazel-out/darwin-fastbuild/bin/main/_objs/hello-greet/hello-greet.d '-DBAZEL_CURRENT_REPOSITORY=""' '-frandom-seed=bazel-out/darwin-fastbuild/bin/main/_objs/hello-greet/hello-greet.o' -isysroot __BAZEL_XCODE_SDKROOT__ -F__BAZEL_XCODE_SDKROOT__/System/Library/Frameworks -F__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/MacOSX.platform/Developer/Library/Frameworks -no-canonical-prefixes -pthread -no-canonical-prefixes -Wno-builtin-macro-redefined '-D__DATE__="redacted"' '-D__TIMESTAMP__="redacted"' '-D__TIME__="redacted"' -target x86_64-apple-macosx13.1 -c main/hello-greet.cc -o bazel-out/darwin-fastbuild/bin/main/_objs/hello-greet/hello-greet.o)
# Configuration: a42135a42aad3da7e3af209ce54745fb0d0306dc29e1f3dc84d7d58372421fc9
# Execution platform: @local_config_platform//:host
Target //main:hello-world up-to-date:
  bazel-bin/main/hello-world
INFO: Elapsed time: 0.750s, Critical Path: 0.58s
INFO: 2 processes: 1 internal, 1 darwin-sandbox.
INFO: Build completed successfully, 2 total actions

其间依靠如下图

多个软件包,多个方针

在包括多个软件包的状况下又该怎么编译呢?其结构如下:

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

lib目录下的BUILD文件如下

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

main目录下的BUILD文件如下

load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
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 方针依靠于 lib 软件包中的 hello-time 方针(因此是方针标签 //lib:hello-time)- Bazel 经过 deps 特点知道这一点。依靠项图中反映了这一点:

为了顺利构建,请运用可见性特点使 lib/BUILD 中的 //lib:hello-time 方针清晰对 main/BUILD 中的方针可见。这是因为默认状况下,方针仅对同一 BUILD 文件中的其他方针可见。Bazel 运用方针可见性来防止呈现包括完成细节的库走漏到公共 API 等问题。

最后

这篇文章首要介绍了构造体系bazel的简略运用,更多文章能够关注公众号QStack。