見出し画像

Bazel 入門 (2) ターゲットとパッケージ

「Bazel」のターゲットとパッケージについてまとめました。

前回

「Bazel」は、小さなプロジェクトの場合は単一のターゲットで十分ですが、大きなプロジェクトの場合は複数の「ターゲット」と「パッケージ」に分割することで、高速インクリメンタルビルド(変更されたもののみをリビルド)を可能にし、ビルドを高速化することができます。
(情報源)

1. ターゲットとパッケージ

今回は、次の3つのサンプルを作成します。

(1)単一のパッケージの単一のターゲットをビルド
(2)プロジェクトを複数のターゲットに分割してビルド
(3)プロジェクトを複数のパッケージに分割してビルド

2. 単一のパッケージの単一のターゲットをビルド

(1)フォルダ構成
今回のプロジェクトは、以下のようなフォルダ構成になります。

└──stage1
   ├── main
   │   ├── BUILD
   │   └── helloworld.cpp
   └── WORKSPACE

(2) WORKSPACEファイルを作成
「WORKSPACE」ファイルの中身は今回は必要ないので空とします。

(3)BUILDファイルを作成
単一のターゲットのビルド設定を行います。

【BUILD】

cc_binary(
    name = "helloworld",
    srcs = ["helloworld.cpp"],
)

(4)ソースコードの作成
ソースコードの中身は次のように記述します。
「Hello world」と「時間」を表示するコードになります。

【helloworld.cpp】

#include <ctime>
#include <string>
#include <iostream>

std::string get_greet(const std::string& who) {
  return "Hello " + who;
}

void print_localtime() {
  std::time_t result = std::time(nullptr);
  std::cout << std::asctime(std::localtime(&result));
}

int main(int argc, char** argv) {
  std::string who = "world";
  if (argc > 1) {
    who = argv[1];
  }
  std::cout << get_greet(who) << std::endl;
  print_localtime();
  return 0;
}

(5)ビルド
ビルドのコマンドは次の通りです。
「/.bazel-bin/main/」にビルド結果が出力されます。

$ bazel build //main:helloworld

(6)実行
以下のコマンドで実行できます。

$ bazel run //main:helloworld
Hello world
Tue Oct 22 08:33:19 2019

3. プロジェクトを複数のターゲットに分割してビルド

プロジェクトを2つの「ターゲット」に分割してビルドします。

(1)フォルダ構成
今回のプロジェクトは、以下のようなフォルダ構成になります。

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

(2) WORKSPACEファイルを作成
「WORKSPACE」ファイルの中身は今回は必要ないので空とします。

(3)BUILDファイルを作成
複数のターゲットのビルド設定を行います。属性「name」はターゲット名、「srcs」はソースコード、「hdrs」はヘッダファイル、「deps」は依存関係になります。「helloworld」ターゲットのビルドには「greet」ターゲットが必要なため、depsに[":greet"]を指定しています。ターゲットは「//<パッケージのパス>:<ターゲット名>」で指定しますが、同一パッケージのターゲットでは「//<パッケージのパス>」を省略できます。

【BUILD】

cc_library(
    name = "greet",
    srcs = ["greet.cpp"],
    hdrs = ["greet.h"],
)

cc_binary(
    name = "helloworld",
    srcs = ["helloworld.cpp"],
    deps = [
        ":greet",
    ],
)

(4)ソースコードの作成
ソースコードの中身は次のように記述します。

【greet.h】

#ifndef LIB_GREET_H_
#define LIB_GREET_H_

#include <string>

std::string get_greet(const std::string &thing);

#endif

【greet.cpp】

#include "greet.h"
#include <string>

std::string get_greet(const std::string& who) {
  return "Hello " + who;
}

【helloworld.cpp】

#include "greet.h"
#include <ctime>
#include <iostream>
#include <string>

void print_localtime() {
  std::time_t result = std::time(nullptr);
  std::cout << std::asctime(std::localtime(&result));
}

int main(int argc, char** argv) {
  std::string who = "world";
  if (argc > 1) {
    who = argv[1];
  }
  std::cout << get_greet(who) << std::endl;
  print_localtime();
  return 0;
}

(5)ビルド
ビルドのコマンドは次の通りです。「/.bazel-bin/main/」にビルド結果が出力されます。

$ bazel build //main:helloworld

(6)実行
以下のコマンドで実行できます。

$ bazel run //main:helloworld
Hello world
Tue Oct 22 08:33:19 2019

4. プロジェクトを複数のパッケージに分割してビルド

プロジェクトを複数のパッケージに分割してビルドします。

(1)フォルダ構成
今回のプロジェクトは、以下のようなフォルダ構成になります。

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

(2) WORKSPACEファイルを作成
「WORKSPACE」ファイルの中身は今回は必要ないので空とします。

(3)BUILDファイルを作成
複数のパッケージのビルド設定を行います。属性「visibility」は可視化属性で、「main」ターゲットからアクセスできるようにしています。「helloworld」ターゲットのビルドには「greet」ターゲットと別パッケージの「time」ターゲットが必要なため、depsに[":greet", "//lib:time",]を指定しています。

【lib/BUILD】

cc_library(
    name = "time",
    srcs = ["time.cpp"],
    hdrs = ["time.h"],
    visibility = ["//main:__pkg__"],
)

【main/BUILD】

cc_library(
    name = "greet",
    srcs = ["greet.cpp"],
    hdrs = ["greet.h"],
)

cc_binary(
    name = "helloworld",
    srcs = ["helloworld.cpp"],
    deps = [
        ":greet",
        "//lib:time",
    ],
)

(4)ソースコードの作成
ソースコードの中身は次のように記述します。「Hello world」と時間を表示するコードになります。

【lib/time.h】

#ifndef LIB_TIME_H_
#define LIB_TIME_H_

void print_localtime();

#endif

【lib/time.cpp】

#include "lib/time.h"
#include <ctime>
#include <iostream>

void print_localtime() {
  std::time_t result = std::time(nullptr);
  std::cout << std::asctime(std::localtime(&result));
}

【main/greet.h】

#ifndef MAIN_GREET_H_
#define MAIN_GREET_H_

#include <string>

std::string get_greet(const std::string &thing);

#endif

【main/greet.cpp】

#include "main/greet.h"
#include <string>

std::string get_greet(const std::string& who) {
  return "Hello " + who;
}

【main/helloworld.cpp】

#include "lib/time.h"
#include "main/greet.h"
#include <iostream>
#include <string>

int main(int argc, char** argv) {
  std::string who = "world";
  if (argc > 1) {
    who = argv[1];
  }
  std::cout << get_greet(who) << std::endl;
  print_localtime();
  return 0;
}

(5)ビルド
ビルドのコマンドは次の通りです。パッケージが2つなので、「/.bazel-bin/main/」と「/.bazel-bin/main/lib/」にビルド結果が出力されます。

$ bazel build //main:helloworld

(6)実行
以下のコマンドで実行できます。

$ bazel run //main:helloworld
Hello world
Tue Oct 22 08:33:19 2019

次回


この記事が気に入ったらサポートをしてみませんか?