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

7.3 · 7.2 · 7.1 · 7.0 · 6.5

このページでは、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/...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 がある場合、後者は前者のビルドの一部としてビルドされます。

bazel buildbazel test などのコマンドで指定された場合、tags = ["manual"] を含むターゲットはワイルドカード ターゲット パターン(...:*: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 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 プロジェクトのビルド時にのみバンドル解除され、フェッチされます。

ただし、これらの暗黙的な依存関係により、すべての 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 をエアギャップのある環境にコピーできるディレクトリにエクスポートします。--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 などで使用されるツールなど)もビルドする必要があります。これらのツールは、ワークステーションで実行するようにビルドする必要があります。したがって、ビルド中に実行するツールをビルドするために使用されるホスト構成と、ターゲット構成(またはリクエスト構成。ただし、この単語にはすでに多くの意味がありますが、より頻繁に「ターゲット構成」と呼ぶ頻度が多くあります。ホスト構成は、最終的にリクエストしたバイナリをビルドするために使用する構成です。

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

Bazel は、--distinct_host_configuration オプションに基づいて、次の 2 つの方法のいずれかでホスト構成を選択します。このブール値オプションは微妙な部分があり、この設定によってビルド速度が向上(または低下)する可能性があります。

--distinct_host_configuration=false

このオプションが false の場合、ホスト構成とリクエスト構成は同じになります。ビルド中に必要なツールはすべて、ターゲット プログラムとまったく同じ方法でビルドされます。この設定により、1 回のビルドでライブラリを 2 回ビルドする必要がなくなります。

ただし、リクエスト構成の変更はホスト構成にも影響し、すべてのツールが再ビルドされ、ツールの出力に依存するすべてのものが再ビルドされます。したがって、たとえばビルド間でリンカー オプションを変更するだけで、すべてのツールが再リンクされ、そのツールを使用するすべてのアクションが再実行され、非常に大規模な再ビルドが発生する可能性があります。

--distinct_host_configuration=true (デフォルト)

このオプションが true の場合、ホストとリクエストに同じ構成を使用する代わりに、完全に異なるホスト構成が使用されます。ホスト構成は、次のようにターゲット構成から派生します。

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

リクエスト構成から個別のホスト構成を選択するほうが望ましい理由はさまざまです。一部はここで説明するには難解ですが、2 つは注目に値します。

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

2 つ目は、すべてのビルドでホスト構成とリクエスト構成を分離することで、前述のようにリクエスト構成に軽微な変更(リンカー オプションの変更など)を加えた場合に発生する非常に費用のかかる再ビルドを回避できます。

ただし、特定のビルドでは、このオプションが障害になる場合があります。特に、構成の変更頻度が低いビルド(特に特定の Java ビルド)や、ホスト構成とターゲット構成の両方でビルドする必要があるコードの量が多いビルドでは、メリットが得られない可能性があります。

増分再ビルドを修正

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 などの一部のプラットフォームでは、セキュリティ上の懸念から、ユーザー 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 のようなメッセージが出力される障害です。その場合は、--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 時間以上に及びます。このフェーズで報告されるエラーには、ソースファイルの欠落、ビルド アクションによって実行されたツールのエラー、想定される出力セットを生成するためのツールの障害などがあります。