Bazel を使用してプログラムをビルドする

問題を報告 ソースを表示 Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

このページでは、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 helpstartup_options: Bazel をホストする JVM のオプション。
  • bazel helptarget-syntax: ターゲットを指定する構文について説明します。
  • bazel help info-keys: info コマンドで使用されるキーのリストを表示します。

bazel ツールは、コマンドと呼ばれる多くの機能を実行します。最も一般的に使用されるのは bazel buildbazel 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 ビルドです。何も変更されていないため、再読み込みするパッケージも実行するビルドステップもありません。「foo」またはその依存関係に変更があった場合、Bazel は一部のビルド アクションを再実行するか、増分ビルドを完了します。

複数のターゲットをビルドする

Bazel では、ビルドするターゲットを指定する方法がいくつかあります。これらを総称してターゲット パターンと呼びます。この構文は、buildtestquery などのコマンドで使用されます。

ラベルは、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 次のものと同等です。
  • foo/bar/wiz がパッケージの場合は //foo/bar/wiz:wiz
  • foo/bar がパッケージの場合は //foo/bar:wiz
  • それ以外の場合は //foo: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/...パッケージのワイルドカードで、ディレクトリ foo の下にあるすべてのパッケージを再帰的に示します(パッケージ パスのすべてのルート)。:allターゲットのワイルドカードで、パッケージ内のすべてのルールに一致します。これら 2 つは foo/...:all のように組み合わせることができます。両方のワイルドカードを使用する場合は、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:all-apis//foo/bar:api に依存している場合、//foo/bar:api//foo:all-apis のビルドの一部としてビルドされます。

tags = ["manual"] を含むターゲットは、bazel buildbazel test などのコマンドで指定された場合、ワイルドカード ターゲット パターン(...:*:all など)には含まれません(ただし、否定ワイルドカード ターゲット パターンには含まれます。つまり、除外されます)。Bazel でビルドまたはテストする場合は、コマンドラインで明示的なターゲット パターンを使用して、このようなテスト ターゲットを指定する必要があります。一方、bazel query はこのようなフィルタリングを自動的に行いません(bazel query の目的が損なわれるため)。

外部依存関係をフェッチする

デフォルトでは、Bazel はビルド中に外部依存関係をダウンロードしてシンボリック リンクを作成します。ただし、新しい外部依存関係が追加されたタイミングを知りたい場合や、依存関係を「プリフェッチ」したい場合(オフラインになるフライトの前など)には、この動作が望ましくないことがあります。ビルド中に新しい依存関係が追加されないようにするには、--fetch=false フラグを指定します。このフラグは、ローカル ファイル システム内のディレクトリを指していないリポジトリ ルールにのみ適用されます。たとえば、local_repositorynew_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 fetch を実行する必要はありません。ただし、ワークスペース ディレクトリの外部にあるものを使用している場合、Bazel は bazel build を実行する前に bazel fetch を自動的に実行します。

リポジトリ キャッシュ

Bazel は、同じファイルが異なるワークスペースで必要になる場合や、外部リポジトリの定義が変更されても同じファイルをダウンロードする必要がある場合でも、同じファイルを複数回取得しないようにします。そのため、bazel はリポジトリ キャッシュにダウンロードされたすべてのファイルをキャッシュに保存します。デフォルトでは、これは ~/.cache/bazel/_bazel_$USER/cache/repos/v1/ にあります。場所は --repository_cache オプションで変更できます。キャッシュは、すべてのワークスペースとインストールされているバージョンの bazel で共有されます。Bazel が正しいファイルのコピーを確実に持っている場合、つまり、ダウンロード リクエストでファイルの SHA256 合計が指定され、そのハッシュを持つファイルがキャッシュにある場合、エントリはキャッシュから取得されます。そのため、各外部ファイルのハッシュを指定することは、セキュリティの観点からだけでなく、不要なダウンロードを回避するうえでも有効です。

キャッシュ ヒットごとに、キャッシュ内のファイルの変更時刻が更新されます。これにより、キャッシュ ディレクトリ内のファイルの最終使用日を簡単に特定できます。たとえば、キャッシュを手動でクリーンアップする場合に便利です。キャッシュには、上流で利用できなくなったファイルのコピーが含まれている可能性があるため、キャッシュが自動的にクリーンアップされることはありません。

配布ファイル ディレクトリ

配布ディレクトリは、不要なダウンロードを回避するためのもう 1 つの 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 つ目は、ユーザーまたはビルドツールによって提供される外部データまたは環境データです。ターゲット アーキテクチャの選択、コンパイルとリンクのオプション、その他のツールチェーン構成オプションなどがあります。環境データの完全なセットを構成と呼びます。

1 つのビルドに複数の構成が存在する場合があります。64 ビット アーキテクチャ用の //foo:bin 実行可能ファイルをビルドするが、ワークステーションが 32 ビット マシンであるクロス コンパイルを考えてみましょう。明らかに、ビルドでは 64 ビットの実行可能ファイルを作成できるツールチェーンを使用して //foo:bin をビルドする必要がありますが、ビルドシステムではビルド自体で使用されるさまざまなツール(たとえば、ソースからビルドされ、その後 genrule などで使用されるツール)もビルドする必要があります。これらのツールは、ワークステーションで実行できるようにビルドする必要があります。したがって、2 つの構成を特定できます。1 つは、ビルド中に実行されるツールをビルドするために使用される実行構成です。もう 1 つは、最終的にリクエストしたバイナリをビルドするために使用されるターゲット構成(またはリクエスト構成。ただし、「ターゲット構成」という言葉はすでに多くの意味を持っているにもかかわらず、より頻繁に使用されます)です。

通常、リクエストされたビルド ターゲット(//foo:bin)と 1 つ以上の実行ツール(たとえば、一部のベース ライブラリ)の両方の前提条件となるライブラリが多数あります。このようなライブラリは、実行構成用とターゲット構成用の 2 回ビルドする必要があります。Bazel は、両方のバリアントがビルドされ、派生ファイルが干渉を避けるために分離されるようにします。通常、このようなターゲットは互いに独立しているため、同時にビルドできます。特定のターゲットが 2 回ビルドされていることを示す進行状況メッセージが表示された場合は、これが原因である可能性が最も高くなります。

実行構成は、次のようにターゲット構成から派生します。

  • --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_* オプションを参照)。
  • 他の値はすべてデフォルト値のままにします。

リクエスト構成とは異なる exec 構成を選択する方が望ましい理由はたくさんあります。最も重要なのは次の点です。

まず、ストリップ処理された最適化済みのバイナリを使用することで、ツールのリンクと実行にかかる時間、ツールが占有するディスク容量、分散ビルドでのネットワーク I/O 時間を短縮できます。

第 2 に、すべてのビルドで実行構成とリクエスト構成を分離することで、前述のように、リクエスト構成のわずかな変更(リンカー オプションの変更など)によって発生する非常にコストのかかる再ビルドを回避できます。

増分再ビルドを修正

Bazel プロジェクトの主な目標の 1 つは、正しい増分再ビルドを保証することです。以前のビルドツール、特に Make ベースのツールでは、増分ビルドの実装においていくつかの不健全な前提が立てられています。

まず、ファイルのタイムスタンプが単調に増加します。これは一般的なケースですが、この前提に違反するのは非常に簡単です。ファイルの以前のリビジョンに同期すると、そのファイルの変更時間が短縮され、Make ベースのシステムは再構築されません。

一般に、Make はファイルの変更を検出しますが、コマンドの変更は検出しません。特定のビルドステップでコンパイラに渡されるオプションを変更した場合、Make はコンパイラを再実行しません。make clean を使用して、以前のビルドの無効な出力を手動で破棄する必要があります。

また、Make は、サブプロセスがその出力ファイルへの書き込みを開始した後に、サブプロセスのいずれかが正常に終了しなかった場合に対応できません。現在の Make の実行は失敗しますが、その後の Make の呼び出しでは、切り捨てられた出力ファイルが有効であると盲目的に想定され(入力よりも新しいため)、再構築されません。同様に、Make プロセスが強制終了された場合も、同様の状況が発生する可能性があります。

Bazel は、これらの仮定を回避します。Bazel は、以前に実行されたすべての作業のデータベースを保持します。ビルドステップへの入力ファイル(およびそのタイムスタンプ)のセットと、そのビルドステップのコンパイル コマンドがデータベース内のものと完全に一致し、データベース エントリの出力ファイル(およびそのタイムスタンプ)のセットがディスク上のファイルのタイムスタンプと完全に一致する場合にのみ、ビルドステップを省略します。入力ファイル、出力ファイル、またはコマンド自体に変更を加えると、ビルドステップが再実行されます。

正しい増分ビルドのユーザーにとってのメリットは、混乱による時間の無駄が減ることです。(また、make clean の使用によって発生する再構築の待ち時間が短縮されます。これは、必要な場合と事前に行う場合の両方で当てはまります)。

一貫性と増分ビルドを構築する

正式には、ビルドの状態は、すべての想定される出力ファイルが存在し、その内容がそれらの作成に必要なステップまたはルールで指定されているとおりに正しい場合に、一貫性があると定義します。ソースファイルを編集すると、ビルドの状態は不整合になり、ビルドツールを次に実行して正常に完了するまで不整合の状態が続きます。この状況は一時的なものであり、ビルドツールを実行すると整合性が復元されるため、不安定な不整合と表現します。

もう 1 つの有害な不整合は、安定した不整合です。ビルドが安定した不整合状態に達すると、ビルドツールの呼び出しが繰り返し成功しても整合性は復元されません。ビルドが「スタック」し、出力が正しくないままになります。安定した不整合状態は、Make(およびその他のビルドツール)のユーザーが make clean を入力する主な理由です。ビルドツールがこのように失敗したことを発見し、そこから復元するのは、時間がかかり、非常に面倒な作業です。

概念的には、一貫性のあるビルドを実現する最も簡単な方法は、以前のビルドの出力をすべて破棄して、最初からやり直すことです。つまり、すべてのビルドをクリーンビルドにします。この方法は、実用的とは言えないほど時間がかかります(リリース エンジニアは除く)。そのため、ビルドツールは整合性を損なうことなく増分ビルドを実行できる必要があります。

増分依存関係分析を正しく行うのは難しく、前述のように、他の多くのビルドツールでは、増分ビルド中に安定した一貫性のない状態を回避するのが難しいです。一方、Bazel では、編集を行わずにビルドツールを正常に呼び出した後、ビルドは一貫性のある状態になることが保証されます。(ビルド中にソースファイルを編集した場合、Bazel は現在のビルドの結果の一貫性を保証しません。ただし、次のビルドの結果で整合性が復元されることは保証されます)。

すべての保証と同様に、細かい条件があります。Bazel で安定した不整合状態になる既知の方法がいくつかあります。増分依存関係分析のバグを意図的に見つけようとする試みから生じた問題については調査を保証しませんが、ビルドツールの通常の、または「妥当な」使用から生じた安定した不整合状態についてはすべて調査し、修正に最善を尽くします。

Bazel で安定した一貫性のない状態が検出された場合は、バグを報告してください。

サンドボックス化された実行

Bazel は、アクションが密閉され、正しく実行されることを保証するためにサンドボックスを使用します。Bazel は、ツールがジョブを実行するために必要な最小限のファイルセットのみを含むサンドボックスでスパウン(大まかに言うとアクション)を実行します。現在、サンドボックスは CONFIG_USER_NS オプションが有効になっている Linux 3.12 以降と、macOS 10.11 以降で機能します。

システムがサンドボックス化をサポートしていない場合、Bazel は警告を出力して、ビルドが hermetic であることが保証されず、ホストシステムに予期しない影響を与える可能性があることを通知します。この警告を無効にするには、Bazel に --ignore_unsupported_sandboxing フラグを渡します。

Google Kubernetes Engine クラスタノードや Debian などの一部のプラットフォームでは、セキュリティ上の懸念からユーザー Namespace がデフォルトで無効になっています。これは、ファイル /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 のようなメッセージを出力する障害です。その場合は、genrules のサンドボックスを --strategy=Genrule=standalone で、他のルールのサンドボックスを --spawn_strategy=standalone で無効にしてみてください。また、問題の追跡ツールでバグを報告し、使用している Linux ディストリビューションを明記してください。これにより、調査を行い、次のリリースで修正を提供できます。

ビルドのフェーズ

Bazel では、ビルドは 3 つの異なるフェーズで行われます。ユーザーとして、これらの違いを理解することで、ビルドを制御するオプション(下記を参照)を把握できます。

読み込みフェーズ

1 つ目は読み込みです。このフェーズでは、初期ターゲットに必要なすべての BUILD ファイルと、その依存関係の推移閉包が読み込まれ、解析、評価、キャッシュ保存されます。

Bazel サーバーの起動後の最初のビルドでは、ファイル システムから多くの BUILD ファイルが読み込まれるため、通常、読み込みフェーズに数秒かかります。後続のビルドでは、特に BUILD ファイルが変更されていない場合、読み込みは非常に高速に行われます。

このフェーズで報告されるエラーには、パッケージが見つからない、ターゲットが見つからない、BUILD ファイルの語彙エラーと文法エラー、評価エラーなどがあります。

分析フェーズ

第 2 フェーズの分析では、各ビルドルールのセマンティック分析と検証、ビルド依存関係グラフの構築、ビルドの各ステップで実行する作業の正確な決定が行われます。

読み込みと同様に、分析も全体を計算すると数秒かかります。ただし、Bazel はビルド間の依存関係グラフをキャッシュに保存し、必要なものだけを再分析します。これにより、前回のビルド以降にパッケージが変更されていない場合、増分ビルドを非常に高速に実行できます。

このステージで報告されるエラーには、不適切な依存関係、ルールへの無効な入力、ルール固有のエラー メッセージなどがあります。

Bazel はこの段階で不要なファイル I/O を回避し、実行する作業を決定するために BUILD ファイルのみを読み取るため、読み込みと分析のフェーズは高速です。これは仕様であり、Bazel の query コマンドなど、読み込みフェーズの上に実装される分析ツールの優れた基盤となります。

実施フェーズ

ビルドの 3 番目の最終フェーズは実行です。このフェーズでは、ビルドの各ステップの出力が入力と一致していることを確認し、必要に応じてコンパイル / リンクなどのツールを再実行します。このステップでは、ビルドの大部分の時間が費やされます。大規模なビルドでは数秒から 1 時間以上かかることもあります。このフェーズで報告されるエラーには、ソースファイルの欠落、一部のビルド アクションで実行されるツールでのエラー、ツールが想定される出力セットを生成できないエラーなどがあります。