Bazel

2022年10月30日

はじめに

会社で開発中のソフトウェアをビルドする際に、BazelというGoogle社が開発したビルドツールを利用している。ここでは、Bazelの基本的な動作であったり、覚えておくべきTips、Coverageなどのテスト手法について記載する。

Bazel C++ tutorial

C++プロジェクトをビルドするためのチュートリアルが公式ページに記載されているので、そちらをまず取り組んでみる。
公式ページに記載されていある通り、Bazelを直接インストールするよりはBazelのラッパーであるBazeliskのインストールが推奨されている。Bazeliskを利用することで、プロジェクトごとに適切なバージョンのBazelを使い分けることができる。(Bazelisk公式)

$ sudo apt update
$ sudo apt install -y curl build-essential
#bazeliskをbazelとしてdownload (実行時のコマンドは"bazel"でbazeliskが実行される)
$ curl -L -o bazel https://github.com/bazelbuild/bazelisk/releases/download/v1.14.0/bazelisk-linux-amd64
$ chmod +x bazel
$ export PATH="${PATH}:${PWD}"
$ bazel version

stage1

stage1では単一ターゲット、単一パッケージのビルドを行う。

examples
└── cpp-tutorial
    └──stage1
       ├── main
       │   ├── BUILD
       │   └── hello-world.cc
       └── WORKSPACE
load("@rules_cc//cc:defs.bzl", "cc_binary")

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
)
bazel build //main:hello-world

ビルドを実行すると、bazel-bin/main/配下に"hello-world"の実行バイナリが出力される

stage2

stage2では、複数のビルドターゲットをビルドする。

    ├──stage2
    │  ├── main
    │  │   ├── BUILD
    │  │   ├── hello-world.cc
    │  │   ├── hello-greet.cc
    │  │   └── hello-greet.h
    │  └── WORKSPACE
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",
    ],
)

このBUILDファイルには、Build時にまず"hello-greet"ライブラリをビルドし、そのあとに"hello-world"のビルドが行われることが記載されている。cc_binaryのdepsには"hello-world"のビルドの際に"hello-greet"ライブラリが必要を明示している。ビルド実行コマンドはstage1と同じだ。

stage3

stage3では複数のパッケージをビルドする。

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

mainとlibの二つのパッケージがあり、それぞれにBUILDファイルが存在している。

cc_library(
    name = "hello-time",
    srcs = ["hello-time.cc"],
    hdrs = ["hello-time.h"],
    visibility = ["//main:__pkg__"],
)
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",
    ],
)

mainパッケージの"hello-world"ターゲットは、mainパッケージの"hello-greet"ターゲットとlibパッケージの"hello-time"ターゲットに依存する。
libパッケージのvisibility属性を使用してmain/BUILDのターゲットに明示的に表示する。(デフォルトでは、BUILDファイル内のターゲットのみに表示されるため)
ビルド実行コマンドは、今までのstageと同じ。

Bazel coverage

Bazelにはcoverageコマンドを使用して、コードカバレッジレポートを生成することができる。
今回は、このサブコマンドを使用してsampleコードのカバレッジを取得してみる。

bazel coverage --action_env=COVERAGE_GCOV_OPTIONS=-b --experimental_cc_coverage --combined_report=lcov --coverage_report_generator=@bazel_tools//tools/test/CoverageOutputGenerator/java/com/google/devtools/coverageoutputgenerator:Main //...
genhtml --branch-coverage --demangle-cpp -o coverage-html bazel-out/_coverage/_coverage_report.dat

参考

Bazel公式ページ

Buildツール

Posted by okuribito