Bazel
ビルドツール
Bazel
概要
Bazelは、Google社で開発された高性能でスケーラブルなビルド・テストツールです。元々はGoogleの内部ツール「Blaze」として開発され、2015年にオープンソース化されました。多言語対応(Java、C++、Python、Go、JavaScript、TypeScript等)と大規模プロジェクトに特化した設計が特徴で、増分ビルド、並列処理、分散ビルド、クロスプラットフォーム対応を提供します。TensorFlow、Angular、Envoy等の大規模オープンソースプロジェクトで採用され、エンタープライズ環境での実績も豊富です。
詳細
主要機能
- 高速ビルド: 増分ビルドと並列処理による大幅な時間短縮
- スケーラビリティ: 数百万行のコードベースに対応
- 再現可能ビルド: ハーマライズされた環境での一貫したビルド結果
- 多言語サポート: Java、C++、Python、Go、JavaScript、Android、iOS等
- 分散ビルド: Remote Build Execution (RBE)によるクラウド分散処理
- 詳細な依存関係追跡: 精密な依存関係グラフ構築
- テスト統合: ビルドとテストの統一管理
アーキテクチャ
BUILD.bazelファイルで定義されたターゲットから依存関係グラフを構築し、変更されたターゲットのみを効率的に再ビルド。Sandbox環境での実行により高い再現性を保証。
エコシステム
Bazel Central Registry (BCR)、rules_*(公式ルールセット)、Remote Build Execution、IDE統合(IntelliJ、VS Code)、CI/CDパイプライン統合が充実。
メリット・デメリット
メリット
- 超高速ビルド: 増分ビルドと並列処理により大幅な時間短縮
- スケーラビリティ: 巨大プロジェクトに対応する設計
- 再現性: 環境に依存しない一貫したビルド結果
- 多言語対応: 単一ツールで複数言語を統一管理
- 分散ビルド: クラウドリソースを活用した高速処理
- 詳細な依存関係管理: 正確で効率的な依存関係追跡
- 企業での実績: Google、Dropbox、Uber等での大規模運用実績
デメリット
- 学習コストの高さ: 独特の概念と設定方法の習得が必要
- 設定の複雑さ: 初期設定とルール定義が複雑
- ツールサイズ: 他のビルドツールより大きなインストールサイズ
- エコシステム依存: Bazel専用ルールへの依存
- 小規模プロジェクト: オーバーヘッドが大きい場合も
- デバッグの困難さ: 抽象化されたビルドプロセスの問題追跡
参考ページ
書き方の例
インストールとセットアップ
# Ubuntu/Debian
curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor > bazel.gpg
sudo mv bazel.gpg /etc/apt/trusted.gpg.d/
echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
sudo apt update && sudo apt install bazel
# CentOS/RHEL/Fedora
sudo dnf copr enable vbatts/bazel
sudo dnf install bazel
# macOS (Homebrew)
brew install bazel
# Windows (Chocolatey)
choco install bazel
# バイナリ直接ダウンロード
wget https://github.com/bazelbuild/bazel/releases/download/6.0.0/bazel-6.0.0-installer-linux-x86_64.sh
chmod +x bazel-6.0.0-installer-linux-x86_64.sh
./bazel-6.0.0-installer-linux-x86_64.sh --user
# バージョン確認
bazel version
# プロジェクト初期化
bazel mod init my-project
基本的なWORKSPACE.bazelとBUILD.bazel
# WORKSPACE.bazel (プロジェクトルート)
workspace(name = "my_project")
# Bazel Central Registry使用
bazel_dep(name = "rules_cc", version = "0.0.9")
bazel_dep(name = "rules_java", version = "7.1.0")
bazel_dep(name = "rules_python", version = "0.27.1")
# 外部依存関係(Maven)
bazel_dep(name = "rules_jvm_external", version = "5.3")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
maven.install(
artifacts = [
"junit:junit:4.13.2",
"com.google.guava:guava:31.1-jre",
"org.apache.commons:commons-lang3:3.12.0",
],
repositories = [
"https://repo1.maven.org/maven2",
],
)
# BUILD.bazel (src/main/java ディレクトリ)
load("@rules_java//java:defs.bzl", "java_binary", "java_library")
# Javaライブラリ
java_library(
name = "utils",
srcs = ["Utils.java"],
deps = [
"@maven//:com_google_guava_guava",
"@maven//:org_apache_commons_commons_lang3",
],
visibility = ["//visibility:public"],
)
# Javaアプリケーション
java_binary(
name = "main",
srcs = ["Main.java"],
main_class = "com.example.Main",
deps = [
":utils",
"@maven//:com_google_guava_guava",
],
)
# テスト
java_test(
name = "utils_test",
srcs = ["UtilsTest.java"],
test_class = "com.example.UtilsTest",
deps = [
":utils",
"@maven//:junit_junit",
],
)
C++プロジェクトの設定
# BUILD.bazel (C++プロジェクト用)
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
# C++ライブラリ
cc_library(
name = "math_utils",
srcs = ["math_utils.cpp"],
hdrs = ["math_utils.h"],
visibility = ["//visibility:public"],
)
cc_library(
name = "string_utils",
srcs = ["string_utils.cpp"],
hdrs = ["string_utils.h"],
deps = [":math_utils"],
visibility = ["//visibility:public"],
)
# C++バイナリ
cc_binary(
name = "main",
srcs = ["main.cpp"],
deps = [
":math_utils",
":string_utils",
],
)
# C++テスト(Google Test使用)
cc_test(
name = "math_utils_test",
srcs = ["math_utils_test.cpp"],
deps = [
":math_utils",
"@com_google_googletest//:gtest_main",
],
)
# Google Test依存関係(WORKSPACE.bazel に追加)
# bazel_dep(name = "googletest", version = "1.14.0.bcr.1")
Pythonプロジェクトの設定
# BUILD.bazel (Python用)
load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
# Pythonライブラリ
py_library(
name = "calculator",
srcs = ["calculator.py"],
visibility = ["//visibility:public"],
)
py_library(
name = "utils",
srcs = ["utils.py"],
deps = [":calculator"],
visibility = ["//visibility:public"],
)
# Pythonバイナリ
py_binary(
name = "main",
srcs = ["main.py"],
main = "main.py",
deps = [
":calculator",
":utils",
],
)
# Pythonテスト
py_test(
name = "calculator_test",
srcs = ["calculator_test.py"],
main = "calculator_test.py",
deps = [":calculator"],
)
# 外部Pythonパッケージ(WORKSPACE.bazel に追加)
# bazel_dep(name = "rules_python", version = "0.27.1")
# pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
# pip.parse(
# hub_name = "pip",
# python_version = "3.11",
# requirements_lock = "//:requirements_lock.txt",
# )
マルチ言語プロジェクト
# BUILD.bazel (ルートディレクトリ)
# マルチ言語プロジェクトの統合
# Java web API
java_binary(
name = "api_server",
srcs = glob(["src/main/java/**/*.java"]),
main_class = "com.example.ApiServer",
deps = [
"@maven//:org_springframework_spring_boot_starter_web",
"@maven//:org_springframework_boot_spring_boot_starter",
],
)
# Python data processing
py_binary(
name = "data_processor",
srcs = ["scripts/data_processor.py"],
deps = [
"@pip//numpy",
"@pip//pandas",
],
)
# C++ high-performance computing
cc_binary(
name = "compute_engine",
srcs = glob(["src/cpp/**/*.cpp"]),
hdrs = glob(["src/cpp/**/*.h"]),
deps = [
"@eigen//:eigen3",
"@boost//:system",
],
)
# JavaScript/TypeScript frontend
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")
nodejs_binary(
name = "frontend",
data = [
"package.json",
"@npm//react",
"@npm//react-dom",
] + glob(["src/frontend/**/*"]),
entry_point = "src/frontend/index.js",
)
# 統合テストスイート
test_suite(
name = "all_tests",
tests = [
"//src/main/java:utils_test",
"//scripts:data_processor_test",
"//src/cpp:compute_engine_test",
"//src/frontend:frontend_test",
],
)
高度な設定とカスタムルール
# BUILD.bazel (高度な設定例)
# カスタムルール定義
load("//tools:custom_rules.bzl", "custom_binary")
# プラットフォーム固有ビルド
config_setting(
name = "linux_x86_64",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
)
config_setting(
name = "darwin_arm64",
constraint_values = [
"@platforms//os:macos",
"@platforms//cpu:arm64",
],
)
# 条件付きコンパイル
cc_binary(
name = "platform_specific",
srcs = ["main.cpp"],
deps = select({
":linux_x86_64": [":linux_deps"],
":darwin_arm64": [":macos_deps"],
"//conditions:default": [":default_deps"],
}),
)
# Docker イメージ生成
load("@io_bazel_rules_docker//container:container.bzl", "container_image")
container_image(
name = "app_image",
base = "@java_base//image",
files = [":api_server_deploy.jar"],
cmd = ["java", "-jar", "/api_server_deploy.jar"],
)
# プロファイリングとメトリクス
cc_binary(
name = "profiled_binary",
srcs = ["main.cpp"],
copts = ["-fprofile-generate"],
linkopts = ["-fprofile-generate"],
deps = [":core_lib"],
)
ビルドとテストの実行
# 基本的なビルドコマンド
bazel build //src/main/java:main # 特定ターゲットのビルド
bazel build //... # 全ターゲットのビルド
bazel build //src/... # パッケージ以下の全ビルド
# テスト実行
bazel test //src/main/java:utils_test # 特定テストの実行
bazel test //... # 全テストの実行
bazel test //src/... --test_output=all # 詳細出力付きテスト
# 実行
bazel run //src/main/java:main # バイナリの実行
bazel run //src/main/java:main -- --arg1 value1 # 引数付き実行
# クリーンアップ
bazel clean # ビルドキャッシュクリア
bazel clean --expunge # 全データ削除
# 並列ビルド
bazel build //... --jobs=8 # 8並列でビルド
bazel build //... --local_cpu_resources=4 # CPU使用数制限
# リモートビルド設定
bazel build //... --remote_executor=grpcs://remote-execution-server:443
パフォーマンス最適化設定
# .bazelrc ファイル(プロジェクトルート)
# 基本最適化
build --compilation_mode=opt
build --copt=-O3
build --copt=-DNDEBUG
# 並列処理設定
build --jobs=auto
build --local_cpu_resources=HOST_CPUS-1
build --local_ram_resources=HOST_RAM*0.8
# キャッシュ設定
build --disk_cache=/tmp/bazel-disk-cache
build --repository_cache=/tmp/bazel-repo-cache
# 増分ビルド最適化
build --watchfs
build --experimental_split_coverage_postprocessing
build --experimental_strict_action_env
# デバッグ用設定
build:debug --compilation_mode=dbg
build:debug --copt=-g
build:debug --strip=never
# テスト設定
test --test_output=errors
test --test_summary=detailed
test --test_verbose_timeout_warnings
# リモートビルド設定
build:remote --remote_executor=grpcs://remote-execution-server:443
build:remote --remote_cache=grpcs://remote-cache-server:443
build:remote --google_default_credentials
# プラットフォーム別設定
build:linux --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64
build:macos --platforms=@io_bazel_rules_go//go/toolchain:darwin_amd64
build:windows --platforms=@io_bazel_rules_go//go/toolchain:windows_amd64
CI/CD統合例
# .github/workflows/bazel.yml
name: Bazel Build and Test
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Mount bazel cache
uses: actions/cache@v3
with:
path: |
~/.cache/bazel
key: bazel-${{ runner.os }}-${{ hashFiles('**/WORKSPACE.bazel', '**/*.bzl') }}
restore-keys: |
bazel-${{ runner.os }}-
- name: Install Bazel
run: |
curl -LO "https://github.com/bazelbuild/bazel/releases/download/6.0.0/bazel-6.0.0-linux-x86_64"
chmod +x bazel-6.0.0-linux-x86_64
sudo mv bazel-6.0.0-linux-x86_64 /usr/local/bin/bazel
- name: Build
run: bazel build //...
- name: Test
run: bazel test //... --test_output=all
- name: Coverage
run: bazel coverage //... --combined_report=lcov
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./bazel-out/_coverage/_coverage_report.dat