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

問題を報告 ソースを表示

このページでは、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 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 ビルドです。null build何も変更されていないため、再読み込みするパッケージも実行するビルドステップもありません。「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ターゲットに対するワイルドカードで、パッケージ内のすべてのルールに一致します。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 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 //...

Bazel 7.1 以降では、Bzlmod を有効にしている場合は、次のコマンドを実行して、すべての外部依存関係をフェッチすることもできます。

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 サムがあり、そのハッシュを含むファイルがキャッシュ内にある場合、エントリはキャッシュから削除されます。そのため、各外部ファイルのハッシュを指定することは、セキュリティの観点から良いアイデアであるだけでなく、不必要なダウンロードの回避にも役立ちます。

キャッシュ ヒットごとに、キャッシュ内のファイルの変更時間が更新されます。この方法では、キャッシュ ディレクトリ内のファイルが最後に使用されたかどうかを簡単に判断できます(キャッシュを手動でクリーンアップするなど)。アップストリームで利用できなくなったファイルのコピーが含まれている可能性があるため、キャッシュは自動的にクリーンアップされません。

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

配布ディレクトリは、不要なダウンロードを回避する Bazel のメカニズムの 1 つです。Bazel は、リポジトリ キャッシュの前にディストリビューション ディレクトリを検索します。主な違いは、ディストリビューション ディレクトリは手動で準備する必要があることです。

--distdir=/path/to-directory オプションを使用すると、追加の読み取り専用ディレクトリを指定して、ファイルを取得する代わりに検索できます。ファイル名が URL のベース名と一致し、さらにファイルのハッシュがダウンロード リクエストで指定されたハッシュと等しい場合、ファイルはこのようなディレクトリから取得されます。これは、WORKSPACE 宣言でファイル ハッシュが指定されている場合にのみ機能します。

ファイル名の条件は正確である必要はありませんが、指定したディレクトリごとに候補ファイルの数が 1 つに減ります。このようにすると、配布ファイルのディレクトリを指定することで、ディレクトリ内のファイル数が増えても効率的な状態を維持できます。

エアギャップ環境での Bazel の実行

Bazel のバイナリサイズを小さくするため、初回実行時に Bazel の暗黙的な依存関係がネットワーク経由で取得されます。これらの暗黙的な依存関係には、すべてのユーザーにとって必要なわけではないツールチェーンとルールが含まれています。たとえば、Android ツールはバンドルされておらず、Android プロジェクトのビルド時にのみ取得されます。

ただし、エアギャップ環境で Bazel を実行しているときに、WORKSPACE の依存関係をすべてベンダー化している場合でも、これらの暗黙的な依存関係によって問題が発生する可能性があります。この問題を解決するには、ネットワークにアクセスできるマシンにこれらの依存関係を含む配布ディレクトリを用意し、オフライン アプローチでエアギャップ環境に転送します。

配布ディレクトリを準備するには、--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 では、環境データの完全なセットを構成と呼びます。

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

通常、リクエストされたビルド ターゲット(//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_* オプションを参照)。
  • その他の値はすべてデフォルトのままにします。

リクエスト構成から個別の exec 構成を選択することが望ましい理由はさまざまです。最も重要なこと:

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

次に、すべてのビルドで exec 構成とリクエスト構成を切り離すことで、前述のようにリクエスト構成の軽微な変更(リンカー オプションの変更など)に起因する非常に高コストな再ビルドを回避できます。

増分再ビルドを修正する

Bazel プロジェクトの主な目的の一つは、増分再ビルドを正しく行うことです。以前のビルドツール、特に Make ベースのビルドツールでは、増分ビルドの実装においていくつかの意味不明な前提条件があります。

まず、ファイルのタイムスタンプが単調に増加します。これは典型的なケースですが、この前提に反することはよくあります。ファイルの以前のリビジョンと同期すると、ファイルの変更時間が短縮され、Make ベースのシステムは再ビルドされません。

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

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

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

正しい増分ビルドを使用すると、混乱によって無駄な時間が減るというメリットがあります。(また、必要かプリエンプティブかにかかわらず、make clean の使用による再ビルドの待機時間も短くなります)。

ビルド整合性と増分ビルド

形式的には、想定される出力ファイルがすべて存在し、ファイルの作成に必要な手順またはルールでその内容が正しい場合、ビルドの状態は「一貫性」と定義されます。ソースファイルを編集すると、ビルドの状態は「不整合」と判断され、次にビルドツールを実行して正常に終了するまで不整合が維持されます。このような状況は「不安定な不整合」と表現します。これは一時的なもので、ビルドツールを実行すると整合性が復元されるためです。

悪質な不整合には、安定した不整合もあります。ビルドが安定した不整合状態になった場合、ビルドツールを繰り返し呼び出しても整合性は復元されません。ビルドが「スタック」し、出力が正しくないままになります。Make(およびその他のビルドツール)のユーザーが make clean 型を使用する主な理由は、安定した不整合状態です。この方法でビルドツールが失敗したことを発見する(それから回復する)のは、時間がかかり、とてもストレスを感じる作業です。

概念的には、一貫性のあるビルドを実現する最も簡単な方法は、以前のビルド出力をすべて破棄し、すべてのビルドをクリーンビルドにすることです。このアプローチは明らかに時間がかかり、実用的ではありません。そのため、ビルドツールが整合性を損なうことなく増分ビルドを実行できなければ意味がありません。

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

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

Bazel との安定した不整合状態を見つけた場合は、バグを報告してください。

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

Bazel はサンドボックスを使用して、アクションが密閉型かつ正しく実行されることを保証します。Bazel は、ツールがジョブの実行に必要とする最小限のファイルセットのみを含むサンドボックスで spawns(大まかに言うとアクション)を実行します。現在、サンドボックス化は、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 ディストリビューションをお伝えください。今後のリリースで調査と修正ができるようになります。

ビルドのフェーズ

Bazel では、ビルドは 3 つの異なるフェーズで行われます。ユーザーにとって、両者の違いを理解することで、ビルドを制御するオプションについての知見を得ることができます(下記を参照)。

読み込みフェーズ

1 つ目は読み込みです。この段階では、最初のターゲットに必要なすべての BUILD ファイルと依存関係の推移的クロージャが読み込まれ、解析、評価、キャッシュに保存されます。

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

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

分析フェーズ

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

読み込みと同様に、分析全体の計算時にも数秒かかります。ただし、Bazel は依存関係グラフをあるビルドから次のビルドにキャッシュし、必要な内容のみを再分析します。そのため、以前のビルドからパッケージが変更されていない場合は、増分ビルドが非常に高速になります。

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

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

実施フェーズ

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