見出し画像

Bazel 入門 (3) - ビルド

「Bazel」のビルドについてまとめました。

前回

1. ビルド

Bazelでプロジェクトをビルドするための一般的な使用例をいくつか紹介します。
(情報源)

2. ターゲットに複数のファイルを含める

「glob」を使用することで、単一のターゲットに複数のファイルを含めることができます 。

cc_library(
   name = "build-all-the-files",
   srcs = glob(["*.cc"]),
   hdrs = glob(["*.h"]),
)

Bazelはこのターゲット(サブフォルダを除く)を含む「BUILD」ファイルと同じフォルダにある全ての「.cc」「.h」をビルドします。

3. 推移的なインクルードの使用

ファイルにヘッダーが含まれている場合、ファイルのルールはそのヘッダーのライブラリに依存する必要があります。逆にいうと、『直接依存関係のみを依存関係として指定』する必要があります。

たとえば、「sandwich.h」に「bread.h」が含まれ、「bread.h」に「flour.h」が含まれているとします。「sandwich.h」には、「flour.h」は含まれていないため、「BUILD」ファイルは次のようになります。

cc_library(
    name = "sandwich",    ←サンドイッチ
    srcs = ["sandwich.cc"],
    hdrs = ["sandwich.h"],
    deps = [":bread"],
)

cc_library(
    name = "bread",    ←パン
    srcs = ["bread.cc"],
    hdrs = ["bread.h"],
    deps = [":flour"],
)

cc_library(
    name = "flour",    ←小麦粉
    srcs = ["flour.cc"],
    hdrs = ["flour.h"],
)

この例では、「sandwich」は「bread」に依存し、「bread」は「flour」に依存しています。

4. インクルードパスの追加

ワークスペースのルートからのインクルードパスをルートできない(またはしたくない)場合があります。既存のライブラリには、ワークスペースのパスと一致しないインクルードフォルダが存在する場合があります。

たとえば、次のフォルダ構造があるとします。

└── my-project
   ├── legacy
   │   └── some_lib
   │       ├── BUILD
   │       ├── include
   │       │   └── some_lib.h
   │       └── some_lib.cc
   └── WORKSPACE

Bazelは、「some_lib.h」が「legacy/some_lib/include/some_lib.h」として含まれることを期待しますが、「some_lib.cc」に「some_lib.h」が含まれています。

このインクルードパスを有効にするには、「legacy/some_lib/BUILD」で「some_lib/include」フォルダが「include」フォルダであることを指定する必要があります。

cc_library(
    name = "some_lib",
    srcs = ["some_lib.cc"],
    hdrs = ["include/some_lib.h"],
    copts = ["-Ilegacy/some_lib/include"],
)

これは、ヘッダーファイルに「/」を含める必要がある外部依存関係に役立ちます。

5. 外部ライブラリを含める

「Google Test」を使用しているとします。「WORKSPACE」ファイルのリポジトリ関数のいずれかを使用して、「Google Test」をダウンロードし、リポジトリで使用可能にすることができます。

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
   name = "gtest",
   url = "https://github.com/google/googletest/archive/release-1.7.0.zip",
   sha256 = "b58cb7547a28b2c718d1e38aee18a3659c9e3ff52440297e965f5edffe34b6d0",
   build_file = "@//:gtest.BUILD",
)

次に、「Google Test」のコンパイルに使用する「gtest.BUILD」を作成します。「Google Test」には、「cc_library」ルールをより複雑にする「特別な」要件がいくつかあります。

・「googletest-release-1.7.0/src/gtest-all.cc」は「googletest-release-1.7.0/src/」に含まれるため、シンボル重複によるリンクエラーが発生しないように、コンパイルから除外する必要があります。
・「googletest-release-1.7.0/include/」(gtest/gtest.h)に関連するヘッダーファイルを使用するため、そのフォルダをインクルードパスに追加する必要があります。
・pthreadでリンクする必要があるため、linkoptとして追加します。

したがって、最終的なルールは次のようになります。

cc_library(
    name = "main",
    srcs = glob(
        ["googletest-release-1.7.0/src/*.cc"],
        exclude = ["googletest-release-1.7.0/src/gtest-all.cc"]
    ),
    hdrs = glob([
        "googletest-release-1.7.0/include/**/*.h",
        "googletest-release-1.7.0/src/*.h"
    ]),
    copts = [
        "-Iexternal/gtest/googletest-release-1.7.0/include"
    ],
    linkopts = ["-pthread"],
    visibility = ["//visibility:public"],
)

これはやや面倒です。アーカイブ構造の副産物として、すべてに「googletest-release-1.7.0」という接頭辞が付きます。「strip_prefix」属性を追加して、「http_archive」にこのプレフィックスを削除させることができます。

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "gtest",
    url = "https://github.com/google/googletest/archive/release-1.7.0.zip",
    sha256 = "b58cb7547a28b2c718d1e38aee18a3659c9e3ff52440297e965f5edffe34b6d0",
    build_file = "@//:gtest.BUILD",
    strip_prefix = "googletest-release-1.7.0",
)

gtest.BUILDは次のようになります。

cc_library(
    name = "main",
    srcs = glob(
        ["src/*.cc"],
        exclude = ["src/gtest-all.cc"]
    ),
    hdrs = glob([
        "include/**/*.h",
        "src/*.h"
    ]),
    copts = ["-Iexternal/gtest/include"],
    linkopts = ["-pthread"],
    visibility = ["//visibility:public"],
)

cc_ rulesは@gtest//:mainに依存できるようになりました。

6. C++テストの作成と実行

たとえば、次のようなテスト「./test/hello-test.cc」を作成できます。

#include "gtest/gtest.h"
#include "lib/hello-greet.h"

TEST(HelloTest, GetGreet) {
  EXPECT_EQ(get_greet("Bazel"), "Hello Bazel");
}

次に、テスト用の「./test/BUILD」を作成します。

cc_test(
    name = "hello-test",
    srcs = ["hello-test.cc"],
    copts = ["-Iexternal/gtest/include"],
    deps = [
        "@gtest//:main",
        "//main:hello-greet",
    ],
)

「hello-greet」を「hello-test」から見えるようにするには、「./main/BUILD」を可視属性にするため「//test:__pkg__」を追加する必要があります。これで、Bazelを使用してテストを実行できます。

$ bazel test test:hello-test

次のように出力されます。

INFO: Found 1 test target...
Target //test:hello-test up-to-date:
 bazel-bin/test/hello-test
INFO: Elapsed time: 4.497s, Critical Path: 2.53s
//test:hello-test PASSED in 0.3s

Executed 1 out of 1 tests: 1 test passes.

7. プリコンパイルされたライブラリへの依存関係の追加

コンパイルされたバージョン(たとえば、ヘッダーと.soファイル)しか持たないライブラリを使用する場合は、「cc_library」ルールでラップします。

cc_library(
    name = "mylib",
    srcs = ["mylib.so"],
    hdrs = ["mylib.h"],
)

ワークスペース内の他のC++ターゲットはこのルールに依存できます。


いいなと思ったら応援しよう!