このページでは、Bazel を使用してプログラムをビルドする方法、ビルドコマンドの構文、ターゲット パターンの構文について説明します。
クイックスタート
Bazel を実行するには、ベース workspace ディレクトリまたはそのサブディレクトリのいずれかに移動して、「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 ビルドです。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 に相当します。 |
デフォルトでは、再帰ターゲット パターンについてはディレクトリ シンボリック リンクに従います。ただし、出力ベースの下で参照しているシンボリック リンク(ワークスペースのルート ディレクトリで作成されたコンビニエンス シンボリック リンクなど)を除きます。
また、Bazel は、DONT_FOLLOW_SYMLINKS_WHEN_TRAVERSING_THIS_DIRECTORY_VIA_A_RECURSIVE_TARGET_PATTERN
という名前のファイルを含むディレクトリで再帰ターゲット パターンを評価するときに、シンボリック リンクを追跡しません。
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 //...
Bazel 7 以降で Bzlmod が有効になっている場合、次のコマンドを実行して、すべての外部依存関係を取得することもできます。
bazel fetch
使用しているすべてのツール(ライブラリ JAR から JDK 自体まで)がワークスペースのルートにある場合、bazel 取得を実行する必要はありません。ただし、ワークスペース ディレクトリ以外で使用している場合は、bazel build
を実行する前に Bazel が自動的に 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 プロジェクトをビルドする場合にのみ取得されます。
ただし、すべての外部依存関係をベンダリングしても、エアギャップのある環境で Bazel を実行すると、これらの暗黙的な依存関係が原因で問題が発生する可能性があります。この問題を解決するには、ネットワーク アクセスが可能なマシン上に、これらの依存関係を含むリポジトリ キャッシュ(Bazel 7 以降)またはディストリビューション ディレクトリ(Bazel 7 より前)を準備し、オフラインでエアギャップのある環境に転送します。
リポジトリ キャッシュ(Bazel 7 以降)
リポジトリ キャッシュを準備するには、--repository_cache
フラグを使用します。暗黙的な依存関係はリリースごとに異なる可能性があるため、新しい Bazel バイナリ バージョンごとに 1 回行う必要があります。
エアギャップ環境の外部で依存関係を取得するには、まず空のワークスペースを作成します。
mkdir empty_workspace && cd empty_workspace
touch MODULE.bazel
touch WORKSPACE
組み込みの Bzlmod 依存関係を取得するには、次のコマンドを実行します。
bazel fetch --repository_cache="path/to/repository/cache"
引き続き以前の WORKSPACE ファイルを使用する場合は、組み込みの WORKSPACE 依存関係を取得するには、次のコマンドを実行します。
bazel sync --repository_cache="path/to/repository/cache"
最後に、エアギャップのある環境で Bazel を使用する場合は、同じ --repository_cache
フラグを渡します。便宜上、.bazelrc
エントリとして追加できます。
common --repository_cache="path/to/repository/cache"
また、Bazel がインターネット経由で BCR にアクセスできないようにするには、ローカルで BCR のクローンを作成し、--registry
フラグを使用してローカルコピーを指定する必要もあります。.bazelrc
に次の行を追加します。
common --registry="path/to/local/bcr/registry"
ディストリビューション ディレクトリ(7 より前の 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 をエアギャップのある環境にコピーできるディレクトリにエクスポートします。--strip-components
フラグに注意してください。--distdir
は、ディレクトリのネストレベルで非常に細かな場合があります。
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 では、完全な環境データを構成と呼んでいます。
1 つのビルドに複数の構成が存在する場合があります。たとえば、クロスコンパイルでは、64 ビット アーキテクチャの //foo:bin
実行可能ファイルをビルドしますが、ワークステーションは 32 ビットマシンです。ビルドでは、64 ビット実行可能ファイルを作成できるツールチェーンを使用して //foo:bin
をビルドする必要がありますが、ビルドシステムは、ビルド自体で使用されるさまざまなツールもビルドする必要があります。たとえば、ソースからビルドされ、genrule で使用されるツールなどがあり、これらはワークステーションで実行するためにビルドする必要があります。したがって、ビルド中に実行するツールをビルドするために使用される実行構成と、ターゲット構成(またはリクエスト構成ですが、この単語はすでに多くの意味がありますが、より頻繁に「ターゲット構成」と呼ぶことがよくあります)という 2 つの構成を識別できます。最終的にリクエストしたバイナリをビルドするために使用する構成です。
通常、リクエストされたビルド ターゲット(//foo:bin
)と 1 つ以上の実行ツール(一部のベースライブラリなど)の前提条件となるライブラリは多数あります。このようなライブラリは、実行構成用に 1 回、ターゲット構成用に 1 回、合計 2 回ビルドする必要があります。Bazel では、両方のバリアントがビルドされていること、干渉を避けるために派生ファイルが分離されていることが確認されます。通常、このようなターゲットは互いに独立しているため、同時にビルドできます。特定のターゲットが 2 回ビルドされていることを示す進行状況メッセージが表示された場合は、これが原因と思われます。
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_*
オプションを参照)。 - その他の値はすべてデフォルトのままにします。
リクエスト構成とは異なる実行構成を選択することが望ましい理由はさまざまです。最も重要な点:
まず、ストリップされて最適化されたバイナリを使用することで、ツールのリンクと実行にかかる時間、ツールが占有するディスク容量、分散ビルドでのネットワーク I/O 時間が削減されます。
次に、すべてのビルドで exec 構成と request 構成を分離することで、前述したようにリクエスト構成の軽微な変更(リンカー オプションの変更など)による、コストのかかる再ビルドを回避できます。
増分再ビルドを修正
Bazel プロジェクトの主な目標の 1 つは、増分再ビルドが正しく行われるようにすることです。以前のビルドツール、特に Make をベースとしたビルドツールでは、増分ビルドの実装において、不適切な前提がいくつか存在します。
まず、ファイルのタイムスタンプは単調に増加します。これは一般的なケースですが、この前提から外れがちです。ファイルの以前のリビジョンと同期すると、そのファイルの変更時間が短縮されます。Make ベースのシステムは再構築されません。
一般的に、Make はファイルの変更を検出しますが、コマンドの変更は検出しません。特定のビルドステップでコンパイラに渡されるオプションを変更した場合、Make はコンパイラを再実行しないため、make clean
を使用して以前のビルドの無効な出力を手動で破棄する必要があります。
また、Make は、サブプロセスが出力ファイルへの書き込みを開始した後に、そのサブプロセスのいずれかが正常に終了しなかった場合に堅牢ではありません。現在の Make の実行は失敗しますが、その後の Make の呼び出しでは、切り捨てられた出力ファイルが有効であると見なされ(入力ファイルよりも新しいため)、再ビルドは行われません。同様に、Make プロセスが強制終了された場合も同様の状況が発生する可能性があります。
Bazel では、このような前提条件は回避されています。Bazel は、これまでに行われたすべての作業のデータベースを維持します。ビルドステップへの入力ファイル(とそのタイムスタンプ)のセットと、そのビルドステップのコンパイル コマンドがデータベース内のものと完全に一致し、データベース エントリの出力ファイル(とそのタイムスタンプ)がディスク上のファイルのタイムスタンプと完全に一致する場合にのみ、ビルドステップを省略します。入力ファイルや出力ファイル、あるいはコマンド自体を変更すると、ビルドステップが再実行されます。
正しい増分ビルドを利用するメリットは、混乱によって無駄な時間が減ることです。(また、make
clean
の使用によって発生する再ビルドの待機時間(必要な場合、またはプリエンプティブの場合)が短縮されます)。
ビルドの整合性と増分ビルド
形式的には、想定されるすべての出力ファイルが存在し、作成に必要なステップまたはルールで指定されているとおりに、その内容が正しい場合、ビルドの状態を「整合性」と定義します。ソースファイルを編集すると、ビルドの状態は「不整合」と判断され、次にビルドツールを実行して正常に完了するまで不整合が維持されます。Google では、この状況を「不安定な不整合」と表現しています。これは一時的なものであり、ビルドツールを実行することで整合性が復元されるためです。
有害な別の種類の不整合があります。それは安定した不整合です。ビルドが整合性のない安定した状態に達した場合、ビルドツールを繰り返し呼び出しても整合性は復元されません。ビルドが「停止」し、出力が不正確になります。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
を使用する他のルールのサンドボックスを無効にしてみてください。また、Issue Tracker でバグを報告し、使用している Linux ディストリビューションをお知らせください。Google が調査を行い、今後のリリースで修正を提供いたします。
ビルドのフェーズ
Bazel では、ビルドは 3 つの異なるフェーズで行われます。ユーザーはフェーズ間の違いを理解することで、ビルドを制御するオプションについての分析情報を得られます(下記参照)。
読み込みフェーズ
1 つ目は読み込みです。この読み込み中に、初期ターゲットに必要なすべての BUILD ファイルと、依存関係の推移的なクロージャが、読み込み、解析、評価、キャッシュに保存されます。
Bazel サーバー起動後の最初のビルドでは、ファイル システムから多くの BUILD ファイルが読み込まれるため、読み込みフェーズには通常数秒かかります。それ以降のビルドでは、特に BUILD ファイルが変更されていない場合、読み込みは非常に速く行われます。
このフェーズで報告されるエラーには、package not found、target not found、BUILD ファイルの語彙と文法の誤り、評価エラーがあります。
分析フェーズ
2 番目のフェーズである分析では、各ビルドルールの意味分析と検証、ビルド依存関係グラフの作成、ビルドの各ステップで行う作業の正確な決定が含まれます。
読み込みと同様に、分析全体を計算するときにも数秒かかります。ただし、Bazel は、あるビルドから次のビルドに依存関係グラフをキャッシュに保存し、必要なものを再分析するだけです。そのため、前回のビルドからパッケージが変更されていない場合は、増分ビルドが非常に高速になります。
この段階で報告されるエラーには、不適切な依存関係、ルールへの無効な入力、ルール固有のすべてのエラー メッセージが含まれます。
この段階で Bazel は不要なファイル I/O を回避し、実行する作業を決定するために BUILD ファイルのみを読み取るため、読み込みフェーズと分析フェーズが高速になります。これは意図的なものであり、Bazel は、読み込みフェーズの上に実装される Bazel の query コマンドなどの分析ツールの基盤として適しています。
実施フェーズ
ビルドの 3 番目かつ最後のフェーズは実行です。このフェーズでは、ビルドの各ステップの出力が入力と一致することを確認し、必要に応じてコンパイルやリンクなどのツールを再実行します。このステップでは、ビルドに多くの時間が費やされます。大規模なビルドの場合は数秒から 1 時間以上に及びます。このフェーズで報告されるエラーには、ソースファイルの欠落、ビルド アクションによって実行されたツールのエラー、想定される出力セットを生成するためのツールの障害などがあります。