このページでは、Bazel を使用してプログラムをビルドする方法、ビルドコマンド構文、ターゲット パターン構文について説明します。
クイックスタート
Bazel を実行するには、ベースとなるワークスペース ディレクトリまたはそのサブディレクトリのいずれかに移動し、「bazel
」と入力します。新しいワークスペースを作成する必要がある場合は、ビルドをご覧ください。
bazel help
[Bazel release bazel version]
Usage: bazel command options ...
使用可能なコマンド
analyze-profile
: ビルド プロファイル データを分析します。aquery
: 分析後アクション グラフに対してクエリを実行します。build
: 指定されたターゲットをビルドします。canonicalize-flags
: Bazel フラグを正規化します。clean
: 出力ファイルを削除し、必要に応じてサーバーを停止します。cquery
: 分析後の依存関係グラフのクエリを実行します。dump
: Bazel サーバー プロセスの内部状態をダンプします。help
: コマンドまたはインデックスのヘルプを出力します。info
: bazel サーバーに関するランタイム情報を表示します。fetch
: ターゲットのすべての外部依存関係を取得します。mobile-install
: モバイル デバイスにアプリをインストールします。query
: 依存関係グラフのクエリを実行します。run
: 指定されたターゲットを実行します。shutdown
: Bazel サーバーを停止します。test
: 指定されたテスト ターゲットをビルドして実行します。version
: Bazel のバージョン情報を出力します。
参考情報
bazel help command
:command
のヘルプとオプションを出力します。bazel help
startup_options
: Bazel をホストする JVM のオプション。bazel help
target-syntax
: ターゲットを指定する構文について説明します。bazel help info-keys
: info コマンドで使用されるキーのリストを表示します。
bazel
ツールは、コマンドと呼ばれる多くの機能を実行します。最もよく使用されるのは bazel build
と bazel test
です。bazel help
を使用すると、オンライン ヘルプ メッセージを参照できます。
1 つのターゲットを作成する
ビルドを開始する前に、ワークスペースが必要です。ワークスペースは、アプリケーションのビルドに必要なすべてのソースファイルを含むディレクトリ ツリーです。Bazel では、完全に読み取り専用のボリュームからビルドを実行できます。
Bazel を使用してプログラムをビルドするには、「bazel build
」に続けてビルドするターゲットを入力します。
bazel build //foo
このコマンドを発行して //foo
をビルドすると、次のような出力が表示されます。
INFO: Analyzed target //foo:foo (14 packages loaded, 48 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
bazel-bin/foo/foo
INFO: Elapsed time: 9.905s, Critical Path: 3.25s
INFO: Build completed successfully, 6 total actions
まず、Bazel はターゲットの依存関係グラフ内のすべてのパッケージを読み込みます。これには、宣言された依存関係、ターゲットの BUILD
ファイルに直接リストされたファイル、推移的な依存関係(ターゲットの依存関係の BUILD
ファイルにリストされたファイル)が含まれます。すべての依存関係を特定した後、Bazel は正確性を分析し、ビルド アクションを作成します。最後に、Bazel はビルドのコンパイラとその他のツールを実行します。
ビルドの実行フェーズで、Bazel は進行状況のメッセージを出力します。進行状況メッセージには、開始時の現在のビルドステップ(コンパイラ、リンカーなど)と、ビルド アクションの合計数に対する完了回数が表示されます。ビルドが開始すると、Bazel がアクション グラフ全体を検出するため、アクションの合計数が増えることがよくありますが、その数は数秒以内に安定します。
ビルドの最後に、Bazel はリクエストされたターゲットとそのターゲットが正常にビルドされたかどうか、ビルドできた場合は出力ファイルの場所を出力します。ビルドを実行するスクリプトはこの出力を確実に解析できます。詳細については、--show_result
をご覧ください。
同じコマンドをもう一度入力すると、ビルドがはるかに速く完了します。
bazel build //foo
INFO: Analyzed target //foo:foo (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //foo:foo up-to-date:
bazel-bin/foo/foo
INFO: Elapsed time: 0.144s, Critical Path: 0.00s
INFO: Build completed successfully, 1 total action
これは null buildです。何も変更されていないため、再読み込みするパッケージと実行するビルドステップはありません。「foo」またはその依存関係に変更があった場合、Bazel は一部のビルド アクションを再実行するか、増分ビルドを完了します。
複数のターゲットのビルド
Bazel では、ビルドするターゲットをさまざまな方法で指定できます。これらを総称してターゲット パターンといいます。この構文は、build
、test
、query
などのコマンドで使用されます。
ラベルは BUILD
ファイルで依存関係を宣言する場合などに、個々のターゲットを指定するために使用されますが、Bazel のターゲット パターンは複数のターゲットを指定します。ターゲット パターンは、ワイルドカードを使用してターゲットのセットのラベル構文を一般化したものです。最も単純なケースでは、有効なラベルは有効なターゲット パターンでもあり、1 つのターゲットのセットを識別します。
//
で始まるすべてのターゲット パターンは、現在のワークスペースを基準として解決されます。
//foo/bar:wiz |
単一のターゲット //foo/bar:wiz のみ。 |
//foo/bar |
//foo/bar:bar と同じです。 |
//foo/bar:all |
パッケージ foo/bar 内のすべてのルール ターゲット。 |
//foo/... |
ディレクトリ foo の下のすべてのパッケージのすべてのルール ターゲット。 |
//foo/...:all |
ディレクトリ foo の下のすべてのパッケージのすべてのルール ターゲット。 |
//foo/...:* |
ディレクトリ foo の下のすべてのパッケージ内のすべてのターゲット(ルールとファイル)。 |
//foo/...:all-targets |
ディレクトリ foo の下のすべてのパッケージ内のすべてのターゲット(ルールとファイル)。 |
//... |
ワークスペース内のパッケージ内のすべてのターゲット。これには、外部リポジトリのターゲットは含まれません。 |
//:all |
最上位パッケージ内のすべてのターゲット(ワークスペースのルートに「BUILD」ファイルがある場合)。 |
//
で始まらないターゲット パターンは、現在の作業ディレクトリを基準として解決されます。次の例では、foo
の作業ディレクトリを前提としています。
:foo |
//foo:foo と同じです。 |
bar:wiz |
//foo/bar:wiz と同じです。 |
bar/wiz |
以下と同じです。
|
bar:all |
//foo/bar:all と同じです。 |
:all |
//foo:all と同じです。 |
...:all |
//foo/...:all と同じです。 |
... |
//foo/...:all と同じです。 |
bar/...:all |
//foo/bar/...:all と同じです。 |
デフォルトでは、ディレクトリ シンボリック リンクの後には再帰的なターゲット パターンが適用されます。ただし、ワークスペースのルート ディレクトリで作成された便利なシンボリック リンクなど、出力ベースの下を指すものは除きます。
また、DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN
というファイルを含むディレクトリで再帰的なターゲット パターンを評価する場合、Bazel はシンボリック リンクに従いません。
foo/...
は「packages」に対するワイルドカードで、すべてのパッケージがディレクトリ foo
の下(パッケージパスのすべてのルート)を再帰的に指定します。:all
はターゲットのワイルドカードで、パッケージ内のすべてのルールに一致します。foo/...:all
のようにこの 2 つを組み合わせることができます。両方のワイルドカードを使用する場合は、foo/...
と省略できます。
また、:*
(または :all-targets
)は、一致したパッケージ内のすべてのターゲットに一致するワイルドカードです。java_binary
ルールに関連付けられた _deploy.jar
ファイルなど、通常はルールによってビルドされないファイルも対象に含まれます。
これは、:*
が :all
のスーパーセットを表すことを意味します。この構文では混乱を招く可能性がありますが、_deploy.jar
のようなターゲットをビルドすることが望ましくない、一般的なビルドに使い慣れた :all
ワイルドカードを使用できます。
また、Bazel では、ラベル構文に必要なコロンの代わりにスラッシュを使用できます。これは、Bash のファイル名展開を使用する場合に便利です。たとえば、foo/bar/wiz
は //foo/bar:wiz
(パッケージ foo/bar
がある場合)または //foo:bar/wiz
(パッケージ foo
がある場合)と同等です。
多くの Bazel コマンドは、ターゲット パターンのリストを引数として受け取り、すべて接頭辞否定演算子 -
に従います。これは、前の引数で指定されたセットからターゲットのセットを減算する場合に使用できます。つまり、順序が重要です。たとえば
bazel build foo/... bar/...
は「foo
の下のすべてのターゲットと、bar
の下のすべてのターゲットをビルドする」ことを意味します。
bazel build -- foo/... -foo/bar/...
「foo/bar
の下にあるものを除く、foo
の下にすべてのターゲットをビルドする」ことを意味します(-
で始まる後続の引数が追加オプションとして解釈されないようにするには、--
引数が必要です)。
ただし、この方法でターゲットを減算しても、ターゲットがビルドされていないことが保証されるわけではありません。これは、減算されていないターゲットの依存関係である可能性があるためです。たとえば、他のターゲットが //foo/bar:api
に依存するターゲット //foo:all-apis
がある場合、後者は前者のビルドの一環としてビルドされます。
tags = ["manual"]
を含むターゲットは、bazel build
や bazel test
などのコマンドで指定されている場合、ワイルドカード ターゲット パターン(...
、:*
、:all
など)には含まれません。Bazel でこれらのターゲットをビルド/テストする場合は、コマンドラインで明示的なターゲット パターンを使用してテスト ターゲットを指定する必要があります。これに対して、bazel query
はそのようなフィルタリングを自動的に実行しません(bazel query
の目的が果たされません)。
外部依存関係を取得する
デフォルトでは、Bazel はビルド中に外部依存関係をダウンロードしてシンボリック リンクします。ただし、これは新しい外部依存関係が追加されたタイミングを把握したいときや、依存関係を「プリフェッチ」したいとき(たとえば、オフラインになるフライトの前など)には望ましくない場合があります。ビルド中に新しい依存関係が追加されないようにするには、--fetch=false
フラグを指定します。このフラグは、ローカル ファイル システムのディレクトリを参照しないリポジトリ ルールにのみ適用されます。local_repository
、new_local_repository
、Android SDK と NDK のリポジトリ ルールなどに対する変更は、--fetch
の値に関係なく常に有効になります。
ビルド中にフェッチを許可しないときに、Bazel が新しい外部依存関係を検出した場合、ビルドは失敗します。
bazel fetch
を実行すると、依存関係を手動で取得できます。ビルド中の取得を許可しない場合は、bazel fetch
を実行する必要があります。
- 初めてビルドする場合です。
- 新しい外部依存関係を追加した後。
一度実行すると、WORKSPACE ファイルが変更されるまで再度実行する必要はありません。
fetch
は、依存関係を取得するターゲットのリストを受け取ります。たとえば、これは //foo:bar
と //bar:baz
のビルドに必要な依存関係をフェッチします。
bazel fetch //foo:bar //bar:baz
ワークスペースのすべての外部依存関係を取得するには、次のコマンドを実行します。
bazel fetch //...
ワークスペースのルートに、使用しているすべてのツール(ライブラリ JAR から JDK 自体まで)がある場合、bazel フェッチを実行する必要はありません。ただし、ワークスペース ディレクトリ以外のものを使用している場合、Bazel は bazel build
を実行する前に bazel fetch
を自動的に実行します。
リポジトリ キャッシュ
Bazel は、異なるワークスペースで同じファイルが必要な場合や、外部リポジトリの定義が変更されたものの、ダウンロードに同じファイルが必要な場合でも、同じファイルを複数回取得しないようにします。これを行うために、bazel はダウンロードしたすべてのファイルをリポジトリ キャッシュ(デフォルトでは ~/.cache/bazel/_bazel_$USER/cache/repos/v1/
にあります)にキャッシュします。この場所は --repository_cache
オプションで変更できます。このキャッシュは、すべてのワークスペースとインストール版 bazel で共有されます。正しいファイルのコピーがあることを Bazel が認識している場合、つまり、ダウンロード リクエストに指定されたファイルの SHA256 の合計があり、そのハッシュを含むファイルがキャッシュ内にある場合、エントリはキャッシュから取得されます。そのため、各外部ファイルに対してハッシュを指定することは、セキュリティの観点から良いアイデアであるだけでなく、不必要なダウンロードの回避にも役立ちます。
キャッシュ ヒットごとに、キャッシュ内のファイルの変更時間が更新されます。このようにして、キャッシュ ディレクトリ内のファイルが最後に使用されたかどうかを簡単に確認できます。たとえば、キャッシュを手動でクリーンアップする場合などです。キャッシュにはアップストリームで利用できなくなったファイルのコピーが含まれる可能性があるため、自動的にクリーンアップされることはありません。
配布ファイルのディレクトリ
配布ディレクトリは、不要なダウンロードを回避する Bazel のメカニズムです。Bazel は、リポジトリ キャッシュの前に配布ディレクトリを検索します。主な違いは、配布ディレクトリは手動で準備する必要があることです。
--distdir=/path/to-directory
オプションを使用すると、追加の読み取り専用ディレクトリを指定して、ファイルを取得する代わりに検索できます。ファイル名が URL のベース名と同じで、さらにファイルのハッシュがダウンロード リクエストで指定されたものと等しい場合、そのようなディレクトリからファイルが取得されます。これは、WORKSPACE 宣言でファイル ハッシュが指定されている場合にのみ機能します。
ファイル名の条件は正確性の要件ではありませんが、指定したディレクトリごとに候補ファイルの数が 1 つに減ります。この方法では、配布ファイル ディレクトリを指定することで、ディレクトリ内のファイル数が増えても効率的に作業できます。
エアギャップのある環境での Bazel の実行
Bazel のバイナリサイズを小さくするために、Bazel の暗黙的な依存関係は、初回実行時にネットワーク経由で取得されます。これらの暗黙的な依存関係には、すべてのユーザーが必要としないツールチェーンとルールが含まれています。たとえば、Android ツールはバンドルされておらず、Android プロジェクトのビルド時にのみ取得されます。
ただし、すべての WORKSPACE 依存関係をベンダー化している場合でも、エアギャップ環境で Bazel を実行する場合、これらの暗黙的な依存関係が原因で問題が発生する可能性があります。この問題を解決するには、ネットワークにアクセスできるマシンにこれらの依存関係を含む配布ディレクトリを作成し、オフラインの方法でエアギャップ環境に転送します。
配布ディレクトリを準備するには、--distdir
フラグを使用します。暗黙的な依存関係はリリースごとに異なる場合があるため、この操作は新しい Bazel バイナリ バージョンごとに 1 回行う必要があります。
これらの依存関係をエアギャップ環境の外部でビルドするには、まず適切なバージョンの Bazel ソースツリーをチェックアウトします。
git clone https://github.com/bazelbuild/bazel "$BAZEL_DIR"
cd "$BAZEL_DIR"
git checkout "$BAZEL_VERSION"
次に、特定の Bazel バージョンに対する暗黙的なランタイム依存関係を含む tarball をビルドします。
bazel build @additional_distfiles//:archives.tar
この tarball を、エアギャップ環境にコピーできるディレクトリにエクスポートします。--distdir
はディレクトリのネスト レベルが非常に難しい場合があるため、--strip-components
フラグに注目してください。
tar xvf bazel-bin/external/additional_distfiles/archives.tar \
-C "$NEW_DIRECTORY" --strip-components=3
最後に、エアギャップのある環境で Bazel を使用する場合は、そのディレクトリを指す --distdir
フラグを渡します。利便性を考えて、これを .bazelrc
エントリとして追加できます。
build --distdir=path/to/directory
ビルド構成とクロスコンパイル
特定のビルドの動作と結果を指定するすべての入力は、2 つのカテゴリに分類できます。1 つ目は、プロジェクトの BUILD
ファイルに保存されている本質的な情報(ビルドルール、その属性の値、推移的依存関係の完全なセット)です。2 種類は、ユーザーまたはビルドツールが提供する外部データまたは環境データで、ターゲット アーキテクチャの選択、コンパイルとリンクのオプション、その他のツールチェーンの構成オプションです。Google では、環境データの完全なセットを「構成」と呼びます。
どのビルドにも複数の構成を含めることができます。64 ビット アーキテクチャ用の //foo:bin
実行可能ファイルをビルドしたものの、ワークステーションが 32 ビットマシンであるクロスコンパイルについて考えてみましょう。ビルドでは、64 ビット実行可能ファイルを作成できるツールチェーンを使用して //foo:bin
をビルドする必要がありますが、ビルドシステムは、ビルド自体で使用されるさまざまなツール(ソースからビルドされ、その後 genrule で使用されるツールなど)もビルドする必要があります。また、これらをワークステーションで実行できるようにビルドする必要があります。したがって、2 つの構成を特定できます。exec 構成(ビルド中で実行されるツールのビルドに使用)と、ターゲット構成(または、要求された多くの構成がすでに使用されています。
通常、要求されたビルド ターゲット(//foo:bin
)と 1 つ以上のツール(いくつかのベース ライブラリなど)の両方の前提条件となるライブラリは多数あります。このようなライブラリは、実行構成とターゲット構成に対して複数回ビルドする必要があります。Bazel は、干渉を避けるために、すべてのバリアントがビルドされ、派生ファイルが分離されるようにします。通常、このようなターゲットは互いに独立しているため、同時にビルドできます。特定のターゲットが複数回ビルドされていることを示す進行状況メッセージが表示された場合は、これが原因であると考えられます。
exec 構成は、次のようにターゲット構成から取得されます。
- リクエスト ターゲットの実行プラットフォームが実行構成のターゲット プラットフォームになります。
--host_crosstool_top
が指定されていない限り、リクエスト構成で指定されているものと同じバージョンの Crosstool(--crosstool_top
)を使用します。--cpu
には--host_cpu
の値を使用します(デフォルト:k8
)。- リクエスト構成で指定されているオプションと同じ値(
--compiler
、--use_ijars
)を使用します。--host_crosstool_top
が使用されている場合は、--host_cpu
の値を使用して、ホスト構成の Crosstool でdefault_toolchain
が検索されます(--compiler
は無視されます)。 --javabase
には--host_javabase
の値を使用します。--java_toolchain
には--host_java_toolchain
の値を使用します。- C++ コード(
-c opt
)向けに最適化されたビルドを使用します。 - デバッグ情報を生成しません(
--copt=-g0
)。 - 実行可能ファイルと共有ライブラリ(
--strip=always
)からデバッグ情報を削除します。 - 派生ファイルはすべて、可能なリクエスト構成で使用されるものとは異なる特別な場所に置きます。
- ビルドデータを持つバイナリのスタンプを抑制します(
--embed_*
オプションを参照)。 - その他の値はすべてデフォルトのままにします。
正しい増分再ビルド
Bazel プロジェクトの主な目的の一つは、増分再ビルドを正しく行うことです。以前のビルドツール、特に Make ベースのビルドツールでは、増分ビルドの実装において、いくつかの不自然な想定があります。
まず、ファイルのタイムスタンプが単調に増加します。これは典型的なケースですが、この前提に反することはよくあります。ファイルの以前のリビジョンと同期すると、そのファイルの変更時間が短縮され、Make ベースのシステムは再ビルドされません。
一般的に、Make はファイルの変更を検出しますが、コマンドの変更は検出しません。特定のビルドステップでコンパイラに渡されるオプションを変更した場合、Make はコンパイラを再実行しません。したがって、make clean
を使用して以前のビルドの無効な出力を手動で破棄する必要があります。
また、Make は、サブプロセスが出力ファイルへの書き込みを開始した後に、そのサブプロセスが終了しても失敗しても堅牢ではありません。現在の Make の実行は失敗しますが、その後の Make の呼び出しでは、切り捨てられた出力ファイルが有効である(入力よりも新しいため)と暗黙的に判断され、再ビルドされません。同様に、Make プロセスが強制終了された場合も、同様の状況が発生する可能性があります。
Bazel では、このような前提条件やその他の前提条件を回避できます。Bazel は、これまでに行われたすべての作業のデータベースを保持し、そのビルドステップへの入力ファイルのセット(とそのタイムスタンプ)と、そのビルドステップのコンパイル コマンドがデータベース内のものと完全に一致し、データベース エントリの出力ファイルのセット(とそのタイムスタンプ)がディスク上のファイルのタイムスタンプと完全に一致する場合にのみ、ビルドステップを省略します。入力ファイル、出力ファイル、またはコマンド自体が変更されると、ビルドステップが再実行されます。
適切な増分ビルドを使用すると、混乱によって無駄になる時間が短くなるというメリットがあります。(また、必要かプリエンプティブかにかかわらず、make
clean
の使用による再ビルドの待機時間も短縮されます)。
ビルドの整合性と増分ビルド
形式上は、想定されるすべての出力ファイルが存在し、そのファイルの作成に必要な手順やルールで指定されている内容が正しい場合に、ビルドの状態を「整合性」と定義しています。ソースファイルを編集すると、ビルドの状態は「一貫性がない」と言われ、次にビルドツールを実行して正常に完了するまで整合性のない状態が維持されます。このような状況は「不安定な不整合」と表現します。これは一時的なものであり、ビルドツールを実行すると整合性が復元されるためです。
悪意のある別の種類の不整合として、安定した不整合があります。ビルドが安定した不整合状態になった場合、ビルドツールを繰り返し呼び出しても整合性は復元されません。ビルドが「スタック」して出力が正しくないままです。Make(およびその他のビルドツール)のユーザーが make clean
とタイプする主な理由は、安定した不整合な状態にあります。この方法でビルドツールが失敗したことを発見し、そこから復元することは、時間がかかり、とてもストレスを感じる作業です。
概念的には、一貫性のあるビルドを実現する最も簡単な方法は、以前のビルド出力をすべて捨てて最初からやり直すことです。すべてのビルドをクリーンビルドにします。この方法は、リリース エンジニアの場合を除いて、明らかに時間がかかるため実用的ではありません。実用的であるためには、ビルドツールが整合性を損なうことなく増分ビルドを実行できる必要があります。
適切な増分依存関係の分析は困難です。前述のように、他の多くのビルドツールでも、増分ビルド時の安定した不整合状態が回避され、うまくいきません。一方、Bazel では、ビルドツールが正常に呼び出され、その間編集を行わないという保証があります。(ビルド中にソースファイルを編集した場合、Bazel は現在のビルドの結果の整合性を保証しません。ただし、次のビルドの結果で整合性が復元されることは保証されます)。
すべての保証と同様に、いくつかの注意事項があります。Bazel との安定した不整合状態になる方法はいくつか報告されています。増分依存関係分析でバグを発見しようとする意図的な試みによって生じるそのような問題の調査は保証されませんが、ビルドツールの通常の使用または「合理的」の使用に起因する安定した不整合な状態はすべて調査し、修正するために最善を尽くします。
Bazel との不整合状態が安定した場合は、バグを報告してください。
サンドボックス化された実行
Bazel は、サンドボックスを使用して、アクションが密閉型かつ正しく実行されるようにします。Bazel は、ツールがジョブを実行するために必要な最小限のファイルセットのみを含むサンドボックスでスポーン(大まかに言うとアクション)を実行します。現在、サンドボックス化は CONFIG_USER_NS
オプションを有効にした Linux 3.12 以降と、macOS 10.11 以降で動作します。
システムがサンドボックス化をサポートしていない場合、Bazel は警告を出力し、ビルドが密閉型であることは保証されず、ホストシステムに不明な方法で影響を与える可能性があることを警告します。この警告を無効にするには、--ignore_unsupported_sandboxing
フラグを Bazel に渡します。
Google Kubernetes Engine クラスタノードや Debian などのプラットフォームでは、セキュリティ上の懸念により、ユーザーの名前空間はデフォルトで無効になっています。これは、/proc/sys/kernel/unprivileged_userns_clone
ファイルを確認することで確認できます。ファイルが存在し、0 が含まれている場合、sudo sysctl kernel.unprivileged_userns_clone=1
でユーザーの名前空間を有効にできます。
システムの設定が原因で、Bazel サンドボックスがルールを実行できない場合があります。通常、通常は障害で namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory
のようなメッセージが出力されます。その場合は、--strategy=Genrule=standalone
を使用して genrules で、--spawn_strategy=standalone
でその他のルールでサンドボックスの無効化を試します。また、Google の Issue Tracker でバグを報告し、使用している Linux ディストリビューションをお伝えください。今後のリリースで調査して修正を提供できるように、
ビルドのフェーズ
Bazel では、ビルドは 3 つのフェーズで行われます。ユーザーはこの 2 つのフェーズの違いを理解することで、ビルドを制御するオプションについて把握できます(以下を参照)。
読み込みフェーズ
1 つ目は読み込みです。この間、最初のターゲットに必要なすべての BUILD ファイルと依存関係の推移的なクロージャが読み込まれ、解析、評価、キャッシュに保存されます。
Bazel サーバーを起動した後の最初のビルドでは、通常、多数の BUILD ファイルがファイル システムから読み込まれるため、読み込みフェーズに数秒かかります。後続のビルドでは、特に BUILD ファイルが変更されていない場合、読み込みが非常に迅速に行われます。
このフェーズで報告されるエラーには、パッケージが見つからない、ターゲットが見つからない、BUILD ファイルの字句や文法上のエラー、評価エラーなどがあります。
分析フェーズ
2 番目のフェーズである分析では、各ビルドルールのセマンティック分析と検証、ビルド依存関係グラフの作成、ビルドの各ステップで実施する正確な作業の決定が含まれます。
読み込みと同様に、分析全体の計算にも数秒かかります。ただし、Bazel は、依存関係グラフをあるビルドから次のビルドまでキャッシュに保存し、必要な内容のみを再分析します。これにより、パッケージが以前のビルドから変更されていない場合は、増分ビルドが非常に高速になります。
この段階で報告されるエラーには、不適切な依存関係、ルールへの無効な入力、ルール固有のすべてのエラー メッセージが含まれます。
Bazel はこの段階で不要なファイル I/O を回避し、実行する作業を決定するために BUILD ファイルのみを読み取るため、読み込みフェーズと分析フェーズが高速になります。これは設計によるものであり、Bazel は、読み込みフェーズの上に実装される Bazel の query コマンドなどの分析ツールに適した基盤になります。
実施フェーズ
ビルドの 3 つ目にして最終フェーズは「実行」です。このフェーズでは、ビルドの各ステップの出力と入力の整合性を確保し、必要に応じてコンパイルツールやリンクツールなどを再実行します。このステップではビルドに多くの時間を費やします(大規模なビルドの場合は数秒から 1 時間以上まで)。このフェーズで報告されるエラーには、ソースファイルの欠落、なんらかのビルド アクションによって実行されたツールのエラー、想定される出力セットを生成するためのツールのエラーなどがあります。