Bazel クエリ リファレンス

問題を報告 ソースを表示

このページは、bazel query を使用してビルドの依存関係を分析する際に使用する Bazel Query Language のリファレンス マニュアルです。また、bazel query がサポートする出力形式についても説明します。

実際のユースケースについては、Bazel クエリのハウツーをご覧ください。

その他のクエリ リファレンス

読み込み後フェーズのターゲット グラフで実行される query に加えて、Bazel には、アクション グラフ クエリ構成可能なクエリが含まれています。

アクション グラフのクエリ

アクション グラフのクエリ(aquery)は、分析後の構成済みターゲット グラフで動作し、アクションアーティファクト、それらの関係に関する情報を公開します。aquery は、構成されたターゲット グラフから生成されたアクション/アーティファクトのプロパティに関心がある場合に役立ちます。たとえば、実際に実行されるコマンドや、その入力、出力、ニーモニックなどです。

詳細については、aquery リファレンスをご覧ください。

構成可能なクエリ

従来の Bazel クエリは、読み込み後フェーズのターゲット グラフで実行されるため、構成や関連するコンセプトの概念はありません。特に、select ステートメントが正しく解決されず、SELECT の使用可能なすべての解像度が返されるという点です。ただし、構成可能なクエリ環境 cquery は構成を適切に処理しますが、この元のクエリのすべての機能を提供できるわけではありません。

詳細については、cquery リファレンスをご覧ください。

bazel query の活用方法一般的な例を次に示します。

//foo ツリーが //bar/baz に依存するのはなぜですか?パスを表示:

somepath(foo/..., //bar/baz:all)

すべての foo テストを実行する C++ ライブラリのうち、foo_bin ターゲットに依存しないものはどれですか。

kind("cc_library", deps(kind(".*test rule", foo/...)) except deps(//foo:foo_bin))

トークン: 語彙の構文

クエリ言語の式は、次のトークンで構成されます。

  • キーワード(例: let)。キーワードとは予約語です。それぞれについて以下で説明します。すべてのキーワードは次のとおりです。

  • 単語(「foo/...」、「.*test rule」、「//bar/baz:all」など)。文字シーケンスが「引用符」で囲まれている場合(先頭と末尾が単一引用符 ' または先頭と二重引用符 " で終わる)は、単語です。文字シーケンスが引用符で囲まれていない場合でも、単語として解析される可能性があります。引用符で囲まれていない単語は、アルファベット A ~ Z、数字 0 ~ 9、特殊文字 */@.-_:$~[](アスタリスク、スラッシュ、アット、ピリオド、ハイフン、アンダースコア、コロン、ドル記号、チルダ、左角かっこ、右角かっこ)から抽出された一連の文字です。ただし、引用符で囲まれていない単語をハイフン - またはアスタリスク * で始めることはできません。相対ターゲット名の先頭がこれらの文字であってもです。

    また、引用符で囲まれていない単語には、プラス記号 + や等号 = は使用できません。ただし、ターゲット名ではこれらの文字を使用できます。クエリ式を生成するコードを記述する場合は、ターゲット名を引用符で囲む必要があります。

    ユーザー指定の値から Bazel クエリ式を作成するスクリプトを作成する場合は、引用符が必要です。

     //foo:bar+wiz    # WRONG: scanned as //foo:bar + wiz.
     //foo:bar=wiz    # WRONG: scanned as //foo:bar = wiz.
     "//foo:bar+wiz"  # OK.
     "//foo:bar=wiz"  # OK.
    

    この引用は、シェルで必要とされる次のような引用に加えて適用されることに注意してください。

    bazel query ' "//foo:bar=wiz" '   # single-quotes for shell, double-quotes for Bazel.
    

    キーワードと演算子を引用符で囲むと、通常の単語として扱われます。たとえば、some はキーワードですが、「some」は単語です。foo と "foo" はどちらも単語です。

    ただし、ターゲット名に単一引用符または二重引用符を使用する場合は注意が必要です。1 つ以上のターゲット名を引用する場合は、1 種類の引用符(すべて一重引用符またはすべて二重引用符)のみを使用します。

    Java クエリ文字列の例を次に示します。

      'a"'a'         # WRONG: Error message: unclosed quotation.
      "a'"a"         # WRONG: Error message: unclosed quotation.
      '"a" + 'a''    # WRONG: Error message: unexpected token 'a' after query expression '"a" + '
      "'a' + "a""    # WRONG: Error message: unexpected token 'a' after query expression ''a' + '
      "a'a"          # OK.
      'a"a'          # OK.
      '"a" + "a"'    # OK
      "'a' + 'a'"    # OK
    

    この構文は、ほとんどの場合、引用符が不要になるようにしています。(通常とは異なる)".*test rule" の例では引用符が必要です。これはピリオドで始まり、スペースが含まれています。"cc_library" の引用符は不要ですが、無害です。

  • 句点(かっこ ()、ピリオド .、カンマ , など)。句読点を含む単語(上記の例外を除く)は引用符で囲む必要があります。

引用符で囲まれた単語外の空白文字は無視されます。

Bazel クエリ言語のコンセプト

Bazel クエリ言語は式言語です。すべての式は、ターゲットの部分順序セット、または同等のターゲットのグラフ(DAG)に評価されます。これは唯一のデータ型です。

セットとグラフは同じデータ型を参照しますが、異なる点を強調します。次に例を示します。

  • Set: ターゲットの部分的な順序は重要ではありません。
  • グラフ: ターゲットの部分的な順序は重要です。

依存関係グラフのサイクル

ビルドの依存関係グラフは非巡回にする必要があります。

クエリ言語で使用されるアルゴリズムは、非巡回グラフでの使用を目的としていますが、サイクルに対して堅牢です。サイクルの扱いの詳細は指定されておらず、信頼すべきではありません。

暗黙的な依存関係

BUILD ファイルで明示的に定義されているビルド依存関係に加えて、Bazel は暗黙的な依存関係をルールに追加します。暗黙的な依存関係は、次のように定義できます。

デフォルトでは、bazel query はクエリ結果を計算するときに暗黙的な依存関係を考慮します。この動作は --[no]implicit_deps オプションで変更できます。

クエリは構成を考慮しないため、潜在的なツールチェーン実装は依存関係とみなされず、必要なツールチェーン タイプのみが依存関係とみなされます。ツールチェーンのドキュメントをご覧ください。

健全性

Bazel クエリ言語式は、ビルド依存関係グラフに対して機能します。このグラフは、すべての BUILD ファイル内のすべてのルール宣言によって暗黙的に定義されます。このグラフはやや抽象的なものであり、ビルドのすべてのステップの実行方法を完全に説明するものではないことを理解することが重要です。ビルドを実行するには、構成も必要です。詳しくは、ユーザーガイドの構成のセクションをご覧ください。

Bazel クエリ言語で式を評価した結果は、すべての構成で真となります。つまり、控えめに過剰な近似が行われており、正確ではない可能性があります。たとえば、ビルドでその機能を使用するつもりがなくても、メッセージ変換のサポートに必要なすべてのファイルがクエリ ツールに含まれているため、ビルド中に必要なすべてのソースファイルのセットをクエリ ツールを使用して計算すると、実際よりも多くレポートされる可能性があります。

グラフの順序の保持について

演算では、サブ式から継承された順序制約が保持されます。これは「部分順序保存の法則」と考えることができます。たとえば、特定のターゲットの依存関係の推移的終了を判断するクエリを発行すると、結果セットは依存関係グラフに従って並べ替えられます。そのセットを file という種類のターゲットのみを含めるようにフィルタすると、元のグラフでは実際には直接接続されていないペアがあっても、結果のサブセットに含まれるターゲットのすべてのペア間に同じ推移的な部分順序関係が保持されます。(ビルドの依存関係グラフにファイル ファイルの端はありません)。

ただし、すべての演算子は順序を保持しますが、set 演算など、一部の演算には独自の順序制約がありません。次の式について考えてみましょう。

deps(x) union y

最終的な結果セットの順序は、サブ式の順序に関する制約をすべて保持することが保証されます。つまり、x のすべての推移的な依存関係が相互に正しく順序付けられます。ただし、このクエリでは、y 内のターゲットの順序や、y 内のターゲットに対する deps(x) 内のターゲットの順序は保証されません(ただし、たまたま deps(x) 内にある y 内のターゲットは除きます)。

順序の制約が発生する演算子には、allpathsdepsrdepssomepath、ターゲット パターンのワイルドカード package:*dir/... などがあります。

Sky のクエリ

Sky Query は、指定されたユニバース スコープで動作するクエリモードです。

SkyQuery でのみ使用できる特殊な関数

Sky Query モードには、追加のクエリ関数 allrdepsrbuildfiles があります。これらの関数は、ユニバースのスコープ全体で動作します(そのため、通常のクエリでは意味がありません)。

ユニバース スコープの指定

Sky Query モードを有効にするには、次の 2 つのフラグ(--universe_scope または --infer_universe_scope)と --order_output=no を渡します。--universe_scope=<target_pattern1>,...,<target_patternN> は、ターゲット パターンで指定されたターゲット パターンの推移的クロージャ(加算と減算の両方)をプリロードするようにクエリに指示します。すべてのクエリは、この「スコープ」で評価されます。特に、allrdeps 演算子と rbuildfiles 演算子は、このスコープからの結果のみを返します。--infer_universe_scope は、クエリ式から --universe_scope の値を推測するよう Bazel に指示します。この推定値はクエリ式内の一意のターゲット パターンのリストですが、意図したとおりではない場合があります。次に例を示します。

bazel query --infer_universe_scope --order_output=no "allrdeps(//my:target)"

このクエリ式の一意のターゲット パターンのリストは ["//my:target"] であるため、Bazel はこれを呼び出しと同様に扱います。

bazel query --universe_scope=//my:target --order_output=no "allrdeps(//my:target)"

しかし、--universe_scope を使用したクエリの結果は //my:target のみです。構造上、//my:target の逆依存関係は宇宙に存在しません。その一方で、次の点を考慮してください。

bazel query --infer_universe_scope --order_output=no "tests(//a/... + b/...) intersect allrdeps(siblings(rbuildfiles(my/starlark/file.bzl)))"

これは、定義で特定の .bzl ファイルを使用するターゲットに推移的に依存する一部のディレクトリの下にあるターゲットの tests 展開で、テスト ターゲットを計算しようとする意味のあるクエリ呼び出しです。ここで、--infer_universe_scope は便利です。特に、--universe_scope を選択するためにクエリ式を自分で解析する必要がある場合には便利です。

したがって、allrdepsrbuildfiles などのユニバース スコープの演算子を使用するクエリ式では、必要な動作がある場合にのみ --infer_universe_scope を使用してください。

Sky Query は、デフォルト クエリと比較して、長所と短所があります。主なデメリットは、グラフの順序に従って出力を並べ替えることができないため、特定の出力形式が使用できないことです。その利点は、デフォルト クエリでは使用できない 2 つの演算子(allrdepsrbuildfiles)を利用できることです。また、Sky Query は、新しいグラフを作成するのではなく、Skyframe グラフをイントロスペクトすることでその処理を行います。新しいグラフはデフォルトの実装で行われます。そのため、処理速度が速く、メモリの使用量が少ない状況もあります。

式: 文法の構文とセマンティクス

Bazel クエリ言語の文法は、EBNF 表記法で示されています。

expr ::= word
       | let name = expr in expr
       | (expr)
       | expr intersect expr
       | expr ^ expr
       | expr union expr
       | expr + expr
       | expr except expr
       | expr - expr
       | set(word *)
       | word '(' int | word | expr ... ')'

以下のセクションでは、この文法の各記述について順番に説明します。

ターゲット パターン

expr ::= word

構文上、ターゲット パターンは単語そのものです。これは、順序付けられていないターゲットのセットとして解釈されます。最も単純なターゲット パターンはラベルで、単一のターゲット(ファイルまたはルール)を識別します。たとえば、ターゲット パターン //foo:bar は、1 つの要素(ターゲット)と bar ルールを含むセットに評価されます。

ターゲット パターンは、パッケージとターゲットにワイルドカードを含めるようにラベルを一般化します。たとえば、foo/...:all(または単に foo/...)は、foo ディレクトリの下にあるすべてのパッケージ内のすべてのルールを含むセットを再帰的に評価するターゲット パターンです。bar/baz:all は、bar/baz パッケージ内のすべてのルールを含むセットに対して評価され、サブパッケージは含まないセットと評価されるターゲット パターンです。

同様に、foo/...:* は、foo ディレクトリの下にあるすべてのパッケージ内のすべてのターゲット(ルールとファイル)を含むセットを再帰的に評価するターゲット パターンです。bar/baz:* は、bar/baz パッケージ内のすべてのターゲットを含むセットとして評価されますが、サブパッケージは含まれません。

:* ワイルドカードは、ファイルとルールを照合するため、多くの場合、クエリには :all よりも便利です。逆に、ビルドでは一般的に :all ワイルドカード(foo/... などのターゲット パターンに暗黙的に指定)を使用すると便利です。

bazel query ターゲット パターンは、bazel build ビルド ターゲットと同じように動作します。詳細については、ターゲット パターンを参照するか、「bazel help target-syntax」と入力します。

ターゲット パターンは、シングルトン セット(ラベルの場合)、多数の要素を含むセット(数千個の要素を持つ foo/... の場合)、ターゲット パターンがどのターゲットとも一致しない場合は空のセットに評価されます。

ターゲット パターン式の結果内のすべてのノードは、依存関係の関係に従って正しく相対的に順序付けられます。したがって、foo:* の結果はパッケージ foo 内のターゲットのセットだけでなく、それらのターゲットのグラフでもあります。(結果ノードの他のノードに対する相対的な順序は保証されません)。詳細については、グラフの順序のセクションをご覧ください。

変数

expr ::= let name = expr1 in expr2
       | $name

Bazel クエリ言語では、変数の定義と参照が可能です。let 式の評価結果は expr2 の評価結果と同じで、変数 name の空いている部分はすべて expr1 の値に置き換えられます。

たとえば、let v = foo/... in allpaths($v, //common) intersect $vallpaths(foo/...,//common) intersect foo/... と同じです。

包含する let name = ... 式以外で変数参照 name が発生した場合は、エラーになります。つまり、トップレベル クエリ式に自由変数を含めることはできません。

上記の文法生成では、name は「単語」に似ていますが、C プログラミング言語の正規の識別子であるという制約が追加されています。変数への参照は、先頭に「$」文字を付加する必要があります。

let 式は変数を 1 つだけ定義しますが、変数をネストできます。

ターゲット パターンと変数参照はどちらも 1 つのトークン(単語)のみで構成され、構文上のあいまいさが生じます。ただし、正規の変数名である単語のサブセットは、正規のターゲット パターンである単語のサブセットと重複しないため、意味のあいまいさはありません。

技術的には、let 式はクエリ言語の表現力を高めるものではありません。言語で表現できるクエリは、これらを使用せずに表現することもできます。ただし、多くのクエリの簡潔性が向上し、クエリ評価の効率が向上する可能性もあります。

かっこで囲まれた式

expr ::= (expr)

括弧はサブ式を関連付けて、評価順序を強制します。かっこで囲まれた式は、引数の値に評価されます。

代数集合演算: 積、和、差分の集合

expr ::= expr intersect expr
       | expr ^ expr
       | expr union expr
       | expr + expr
       | expr except expr
       | expr - expr

これら 3 つの演算子は、引数に対する通常の集合演算を計算します。各演算子には 2 つの形式があります。1 つは名義形式(intersect など)で、もう 1 つはシンボリック形式(^ など)です。どちらの形式も同等です。シンボリック形式のほうがすばやく入力できます。(このページの残りの部分では、公称形式を使用します)。

例:

foo/... except foo/bar/...

foo/... と一致し、foo/bar/... には一致しないターゲットのセットを評価します。

同じクエリは次のように記述できます。

foo/... - foo/bar/...

intersect^)と union+)の演算は可換(対称)であり、except-)は非対称です。このパーサーは、3 つの演算子すべてを左結合として扱い、優先順位が同じであるため、括弧が必要になることがあります。たとえば、最初の 2 つの式は同等ですが、3 つ目の式は異なります。

x intersect y union z
(x intersect y) union z
x intersect (y union z)

外部ソースからターゲットを読み取る: set

expr ::= set(word *)

set(a b c ...) 演算子は、ゼロ個以上のターゲット パターンを空白文字(カンマなし)で区切った和集合を計算します。

Bourne シェルの $(...) 機能と組み合わせると、set() は、1 つのクエリの結果を通常のテキスト ファイルに保存し、そのテキスト ファイルを他のプログラム(標準の UNIX シェルツールなど)で操作してから、結果をクエリ ツールに値として導入してさらに処理します。次に例を示します。

bazel query deps(//my:target) --output=label | grep ... | sed ... | awk ... > foo
bazel query "kind(cc_binary, set($(<foo)))"

次の例では、awk プログラムを使用して maxrank 値をフィルタリングすることで、kind(cc_library, deps(//some_dir/foo:main, 5)) が計算されます。

bazel query 'deps(//some_dir/foo:main)' --output maxrank | awk '($1 < 5) { print $2;} ' > foo
bazel query "kind(cc_library, set($(<foo)))"

これらの例では、$(<foo)$(cat foo) の省略形ですが、前の awk コマンドなど、cat 以外のシェルコマンドも使用できます。

関数

expr ::= word '(' int | word | expr ... ')'

クエリ言語にはいくつかの関数が定義されています。関数の名前によって、必要な引数の数と型が決まります。次の関数を使用できます。

依存関係の一時的なクローズ: 依存関係

expr ::= deps(expr)
       | deps(expr, depth)

deps(x) 演算子は、引数セット x の依存関係の推移的クロージャによって形成されるグラフを評価します。たとえば、deps(//foo) の値は、単一ノード foo をルートとする依存関係グラフで、すべての依存関係を含みます。deps(foo/...) の値は、foo ディレクトリの下にあるすべてのパッケージのすべてのルールをルートとする依存関係グラフです。ここで言う「依存関係」とは、ルールとファイルのターゲットのみを意味するため、これらのターゲットの作成に必要な BUILD ファイルと Starlark ファイルはここには含まれません。そのためには、buildfiles 演算子を使用します。

結果のグラフは、依存関係に従って並べ替えられます。詳細については、グラフの順序のセクションをご覧ください。

deps 演算子は、オプションの 2 番目の引数を受け入れます。これは、検索深度の上限を指定する整数リテラルです。したがって、deps(foo:*, 0)foo パッケージ内のすべてのターゲットを返しますが、deps(foo:*, 1) にはさらに foo パッケージ内の任意のターゲットの直接的な前提条件が含まれ、deps(foo:*, 2) にはさらに deps(foo:*, 1) 内のノードから直接到達可能なノードが含まれます。(これらの数値は、minrank 出力形式に表示されるランクに対応しています)。depth パラメータを省略すると、検索は無制限になり、前提条件の反射推移的クロージャが計算されます。

逆依存関係の一時的な終了: rdeps

expr ::= rdeps(expr, expr)
       | rdeps(expr, expr, depth)

rdeps(u, x) 演算子は、ユニバース セット u の推移的クロージャ内で、引数セット x の逆依存関係を評価します。

結果のグラフは、依存関係に従って並べ替えられます。詳細については、グラフの順序のセクションをご覧ください。

rdeps 演算子は、オプションの 3 番目の引数を受け入れます。これは、検索深度の上限を指定する整数リテラルです。結果のグラフには、引数セットの任意のノードから指定した深度以内のノードのみが含まれます。したがって、rdeps(//foo, //common, 1) は、//common に直接依存する //foo の推移的クロージャ内のすべてのノードを評価します。(これらの数値は、minrank 出力形式に表示されるランクに対応しています)。depth パラメータを省略すると、検索は制限されません。

すべての逆依存関係の一時的な終了: allrdeps

expr ::= allrdeps(expr)
       | allrdeps(expr, depth)

allrdeps 演算子は rdeps 演算子と同様に動作しますが、「ユニバース セット」は --universe_scope フラグで個別に指定されるのではなく評価されたものになります。したがって、--universe_scope=//foo/... が渡された場合、allrdeps(//bar)rdeps(//foo/..., //bar) と同等です。

同じパッケージ内の直接的な逆依存関係: same_pkg_direct_rdeps

expr ::= same_pkg_direct_rdeps(expr)

same_pkg_direct_rdeps(x) 演算子は、引数セット内のターゲットと同じパッケージ内にあり、直接依存するターゲットの完全なセットを評価します。

標的のパッケージの取り扱い:兄弟姉妹

expr ::= siblings(expr)

siblings(x) 演算子は、引数セット内のターゲットと同じパッケージ内にあるターゲットの完全なセットを評価します。

任意の選択: 一部

expr ::= some(expr)
       | some(expr, count )

some(x, k) 演算子は、引数セット x から最大 k 個のターゲットを任意に選択し、それらのターゲットのみを含むセットと評価します。パラメータ k は省略可能です。このパラメータを指定しない場合、任意に選択された 1 つのターゲットのみを含むシングルトン セットが返されます。引数セット x のサイズが k より小さい場合は、引数セット x 全体が返されます。

たとえば、式 some(//foo:main union //bar:baz) は、//foo:main または //bar:baz のいずれかを含むシングルトン セットに評価されますが、どちらも定義されていません。式 some(//foo:main union //bar:baz, 2) または some(//foo:main union //bar:baz, 3) は、//foo:main//bar:baz の両方を返します。

引数がシングルトンの場合、some は恒等式関数を計算します。some(//foo:main)//foo:main と同等です。

some(//foo:main intersect //bar:baz) のように、指定された引数セットが空の場合はエラーになります。

パス演算子: somepath、allpaths

expr ::= somepath(expr, expr)
       | allpaths(expr, expr)

somepath(S, E) 演算子と allpaths(S, E) 演算子は、2 つのターゲット セット間のパスを計算します。どちらのクエリも、開始点の集合 S と終点の集合 E の 2 つの引数を受け入れます。somepath は、S のターゲットから E のターゲットへの任意のパスにあるノードのグラフを返します。allpaths は、S のターゲットから E のターゲットへのすべてのパスにあるノードのグラフを返します。

結果のグラフは、依存関係に従って順序付けされています。詳しくは、グラフの順序のセクションをご覧ください。

サムパス
somepath(S1 + S2, E)、考えられる結果は 1 つ。
サムパス
somepath(S1 + S2, E)、別の考えられる結果。
すべてのパス
allpaths(S1 + S2, E)

ターゲットの種類によるフィルタリング: 種類

expr ::= kind(word, expr)

kind(pattern, input) 演算子は、一連のターゲットにフィルタを適用し、想定された種類でないターゲットを破棄します。pattern パラメータは、照合するターゲットの種類を指定します。

たとえば、以下に示す BUILD ファイル(パッケージ p 用)で定義された 4 つのターゲットの種類を次の表に示します。

コード Target 種類
        genrule(
            name = "a",
            srcs = ["a.in"],
            outs = ["a.out"],
            cmd = "...",
        )
      
//p:a genrule ルール
//p:a.in ソースファイル
//p:a.out 生成されたファイル
//p:BUILD ソースファイル

したがって、kind("cc_.* rule", foo/...)foo の下にあるすべての cc_librarycc_binary などのルール ターゲットのセットを評価し、kind("source file", deps(//foo))//foo ターゲットの依存関係の推移的クロージャにあるすべてのソースファイルのセットを評価します。

pattern 引数がないと、パーサーでは source file.*_test などの多くの正規表現が単語と見なされないため、多くの場合、引数が必要です。

package group を照合する場合、末尾が :all のターゲットでは何も結果が得られない可能性があります。代わりに :all-targets を使用してください。

ターゲット名のフィルタリング: フィルタ

expr ::= filter(word, expr)

filter(pattern, input) 演算子は、一連のターゲットにフィルタを適用し、ラベル(絶対形式)がパターンと一致しないターゲットを破棄します。入力のサブセットに対して評価されます。

最初の引数である pattern は、ターゲット名の正規表現を含む単語です。filter 式は、x がセット input のメンバーであり、x のラベル(//foo:bar などの絶対形式)に正規表現 pattern に一致する(固定されていない)一致が含まれるように、すべてのターゲット x を含むセットを評価します。すべてのターゲット名が // で始まるため、^ 正規表現アンカーの代わりに使用できます。

多くの場合、この演算子は intersect 演算子よりも高速で堅牢なものです。たとえば、//foo:foo ターゲットのすべての bar 依存関係を表示するには、次のように評価します。

deps(//foo) intersect //bar/...

ただし、このステートメントでは bar ツリー内のすべての BUILD ファイルの解析が必要になるため、無関係な BUILD ファイルを使用すると時間がかかり、エラーが発生しやすくなります。別の方法は次のようになります。

filter(//bar, deps(//foo))

これは、最初に //foo 依存関係のセットを計算してから、指定されたパターンに一致するターゲットのみをフィルタします。つまり、部分文字列として //bar を含む名前のターゲットです。

filter(pattern, expr) 演算子のもう一つの一般的な用途は、特定のファイルを名前または拡張子でフィルタすることです。例:

filter("\.cc$", deps(//foo))

//foo のビルドに使用されるすべての .cc ファイルのリストが返されます。

ルール属性のフィルタリング: attr

expr ::= attr(word, word, expr)

attr(name, pattern, input) 演算子は、一連のターゲットにフィルタを適用し、ルールではないターゲット、属性 name が定義されていないルール ターゲット、属性値が指定された正規表現 pattern と一致しないルール ターゲットを破棄します。入力のサブセットを評価します。

最初の引数 name は、指定された正規表現パターンと照合するルール属性の名前です。2 番目の引数 pattern は、属性値に対する正規表現です。attr 式は、x がセット input のメンバーであり、定義された属性 name を持つルールであり、属性値に正規表現 pattern に一致する(固定されていない)一致を含む、すべてのターゲット x を含むセットに評価されます。name がオプションの属性であり、ルールで明示的に指定されていない場合は、デフォルトの属性値が比較に使用されます。例:

attr(linkshared, 0, deps(//foo))

この場合、linkshared 属性の使用が許可されているすべての //foo 依存関係(cc_binary ルールなど)を選択し、明示的に 0 に設定するか、まったく設定せずにデフォルト値を 0 に設定する(cc_binary ルールなど)。

リスト型属性(srcsdata など)は、[value<sub>1</sub>, ..., value<sub>n</sub>] 形式の文字列に変換され、[ 角かっこで始まり、] 角かっこで終わります。また、複数の値を区切るには「,」(カンマ、スペース)を使用します。ラベルは、ラベルの絶対形式を使用して文字列に変換されます。たとえば、属性 deps=[":foo", "//otherpkg:bar", "wiz"] は文字列 [//thispkg:foo, //otherpkg:bar, //thispkg:wiz] に変換されます。角かっこは常に存在するため、空のリストでは照合に文字列値 [] が使用されます。例:

attr("srcs", "\[\]", deps(//foo))

空の srcs 属性を持つ //foo 依存関係のすべてのルールが選択されますが、

attr("data", ".{3,}", deps(//foo))

data 属性に 1 つ以上の値を指定する //foo 依存関係のすべてのルールを選択します(//: により、すべてのラベルは 3 文字以上になります)。

list-type 属性で特定の value を持つ //foo 依存関係にあるすべてのルールを選択するには、次のコマンドを使用します。

attr("tags", "[\[ ]value[,\]]", deps(//foo))

これは、value の前の文字が [ またはスペースになり、value の後の文字がカンマまたは ] になるためです。

ルールの公開設定のフィルタリング: 表示

expr ::= visible(expr, expr)

visible(predicate, input) 演算子は、一連のターゲットにフィルタを適用し、必要な可視性のないターゲットを破棄します。

最初の引数 predicate は、出力内のすべてのターゲットを表示する必要があるターゲットのセットです。visible 式は、x がセット input のメンバーになり、predicate x 内のすべてのターゲット yy に見えるように、すべてのターゲット x を含むセットに評価されます。次に例を示します。

visible(//foo, //bar:*)

これは、公開設定の制限に違反することなく、//foo が依存できるパッケージ //bar 内のすべてのターゲットを選択します。

ラベルタイプのルール属性の評価

expr ::= labels(word, expr)

labels(attr_name, inputs) 演算子は、セット inputs 内のいずれかのルールのタイプが「label」または「ラベルのリスト」の属性 attr_name で指定されたターゲットのセットを返します。

たとえば、labels(srcs, //foo) は、//foo ルールの srcs 属性にあるターゲットのセットを返します。inputs セットに srcs 属性を含むルールが複数ある場合は、それらの srcs のユニオンが返されます。

test_suites: テストを展開してフィルタする

expr ::= tests(expr)

tests(x) 演算子は、セット x 内のすべてのテストルールのセットを返します。すべての test_suite ルールが参照される個々のテストのセットに展開され、tagsize によるフィルタリングが適用されます。

デフォルトでは、クエリ評価はすべての test_suite ルールのテスト以外のターゲットを無視します。これは、--strict_test_suite オプションを使用するとエラーに変更できます。

たとえば、kind(test, foo:*) というクエリを指定すると、foo パッケージ内のすべての *_test ルールと test_suite ルールが一覧表示されます。すべての結果は、(定義上)foo パッケージのメンバーです。一方、tests(foo:*) というクエリでは、bazel test foo:* によって実行される個々のテストがすべて返されます。これには、test_suite ルールを介して直接的または間接的に参照される他のパッケージに属するテストが含まれる場合があります。

パッケージ定義ファイル: ビルドファイル

expr ::= buildfiles(expr)

buildfiles(x) 演算子は、セット x 内の各ターゲットのパッケージを定義するファイルのセットを返します。つまり、パッケージごとに、その BUILD ファイルと、load を介して参照するすべての .bzl ファイルを返します。また、これらの load を付けたファイルを含むパッケージの BUILD ファイルも返されます。

通常、この演算子は、指定したターゲットのビルドに必要なファイルまたはパッケージを特定する際に使用されます。通常は、下記の --output package オプションと組み合わせて使用されます。例:

bazel query 'buildfiles(deps(//foo))' --output package

//foo が推移的に依存するすべてのパッケージのセットを返します。

パッケージ定義ファイル: rbuildfiles

expr ::= rbuildfiles(word, ...)

rbuildfiles 演算子は、パス フラグメントのカンマ区切りのリストを受け取り、これらのパス フラグメントに推移的に依存する BUILD ファイルのセットを返します。たとえば、//foo がパッケージの場合、rbuildfiles(foo/BUILD)//foo:BUILD ターゲットを返します。foo/BUILD ファイルに load('//bar:file.bzl'... が含まれている場合、rbuildfiles(bar/file.bzl)//foo:BUILD ターゲットと、//bar:file.bzl を読み込む他の BUILD ファイルのターゲットを返します。

rbuildfiles 演算子のスコープは、--universe_scope フラグで指定されたユニバースです。BUILD ファイルと .bzl ファイルに直接対応していないファイルは、結果に影響しません。たとえば、ソースファイル(foo.cc など)は、BUILD ファイルで明示的に記述されていても無視されます。ただし、シンボリック リンクは尊重されるため、foo/BUILDbar/BUILD へのシンボリック リンクである場合、rbuildfiles(bar/BUILD) は結果に //foo:BUILD を含めます。

rbuildfiles 演算子は、buildfiles 演算子の逆数とほぼ同じです。ただし、この道徳的逆転は一方向で強く保持されます。rbuildfiles の出力は buildfiles の入力と同様です。前者にはパッケージ内の BUILD ファイル ターゲットのみが含まれ、後者にはそのようなターゲットが含まれます。逆方向では対応度が弱くなります。buildfiles 演算子の出力は、すべてのパッケージと に対応するターゲットです。特定の入力に必要な bzl ファイル。ただし、rbuildfiles 演算子の入力はターゲットではなく、ターゲットに対応するパス フラグメントです。

パッケージ定義ファイル: loadfiles

expr ::= loadfiles(expr)

loadfiles(x) 演算子は、セット x 内の各ターゲットのパッケージを読み込むために必要な Starlark ファイルのセットを返します。つまり、パッケージごとに、BUILD ファイルから参照される .bzl ファイルが返されます。

出力形式

bazel query はグラフを生成します。--output コマンドライン オプションを使用して、bazel query でこのグラフを表示するコンテンツ、形式、順序を指定します。

Sky Query で実行する場合は、順序なし出力と互換性のある出力形式のみを使用できます。具体的には、graphminrankmaxrank の出力形式は禁止されています。

出力形式によっては、追加のオプションも使用できます。各出力オプションの名前には、適用する出力形式の接頭辞が付くため、--graph:factored--output=graph が使用されている場合にのみ適用され、graph 以外の出力形式が使用されている場合は無視されます。同様に、--xml:line_numbers は、--output=xml が使用されている場合にのみ適用されます。

結果の順序

クエリ式は常に「グラフの順序保存の法則」に従いますが、結果の表示は、依存関係の順序付けまたは順序付けられずに行うことができます。これは、結果セット内のターゲットやクエリの計算方法には影響しません。これは、結果を stdout に出力する方法にのみ影響します。さらに、依存関係の順序が同等のノードは、アルファベット順に並べられる場合とされない場合があります。--order_output フラグを使用してこの動作を制御できます。(--[no]order_results フラグは、--order_output フラグの機能のサブセットを持つため、非推奨になりました)。

このフラグのデフォルト値は auto で、辞書順で結果が出力されます。ただし、somepath(a,b) を使用すると、結果は deps の順序で出力されます。

このフラグが no で、--outputbuildlabellabel_kindlocationpackageprotoxml のいずれかである場合、出力は任意の順序で出力されます。通常は、この方法のほうが簡単です。ただし、--outputgraphminrankmaxrank のいずれかである場合はサポートされません。これらの形式の場合、Bazel は常に依存関係の順序またはランクで並べ替えられた結果を出力します。

このフラグが deps の場合、Bazel はトポロジ順に結果を出力します。つまり、最初に依存関係があり、その後に依存関係が表示されます。ただし、依存関係の順序で並べ替えられていないノード(一方から他方へのパスがないため)は任意の順序で出力されます。

このフラグが full の場合、Bazel はノードを完全に決定論的な(合計)順序で出力します。まず、すべてのノードがアルファベット順に並べ替えられます。次に、リスト内の各ノードが、アクセスされていないノードへの送信エッジが後続ノードのアルファベット順で走査される、事後深度優先検索の開始として使用されます。最後に、ノードはアクセスされた順に出力されます。

この順序でノードを出力すると遅くなる可能性があるため、決定論が重要な場合にのみ使用してください。

BUILD に表示されるとおりに、ターゲットのソースフォームを出力します。

--output build

このオプションを使用すると、各ターゲットは BUILD 言語で手書きしたものになります。すべての変数と関数呼び出し(glob、マクロなど)が展開されるため、Starlark マクロの効果を確認できます。また、有効な各ルールは generator_namegenerator_function)の値をレポートし、有効なルールを生成するために評価されたマクロの名前を提供します。

出力では BUILD ファイルと同じ構文が使用されますが、有効な BUILD ファイルが生成される保証はありません。

--output label

このオプションを使用すると、結果のグラフ内の各ターゲットの名前(ラベル)のセットが、トポロジ順に 1 行に 1 つのラベルで出力されます(--noorder_results が指定されている場合は、結果の順序に関する注意事項をご覧ください)。(トポロジの順序とは、グラフノードが後続のすべてのノードよりも先に出現する順序です)。もちろん、グラフには多くのトポロジ順序が考えられます(「逆事後順序」は 1 つだけです)。どれが選択されるかは指定されていません。

somepath クエリの出力を出力する場合、ノードが出力される順序はパスの順序になります。

注意: 場合によっては、同じラベルを持つ 2 つの異なるターゲットが存在する場合があります。たとえば、sh_binary ルールとその唯一の(暗黙的な)srcs ファイルの両方が foo.sh と呼ばれることがあります。クエリの結果にこれらのターゲットの両方が含まれている場合、label 形式の出力には重複があるように見えます。label_kind(下記参照)形式を使用する場合、2 つのターゲットは同じ名前ですが、一方の種類は sh_binary rule、もう一方は source file であるという点が明確になります。

--output label_kind

label と同様に、この出力形式では、結果のグラフに各ターゲットのラベルがトポロジ順に出力されますが、ターゲットの種類がラベルの前に出力されます。

--output proto

クエリ出力を QueryResult プロトコル バッファとして出力します。

--output streamed_proto

Target プロトコル バッファの長さで区切られたストリームを出力します。これは、(i)ターゲットが多すぎて 1 つの QueryResult に収まらない場合に、(i)プロトコル バッファのサイズ制限を回避して、Bazel が出力している間に処理を開始するのに役立ちます。

--output textproto

--output proto と同様に、QueryResult プロトコル バッファをテキスト形式で出力します。

--output streamed_jsonproto

--output streamed_proto と同様に、Target プロトコル バッファのストリームを ndjson 形式で出力します。

--output minrank --output maxrank

label と同様に、minrank および maxrank 出力形式では、結果のグラフに各ターゲットのラベルが出力されますが、トポロジ順ではなく、ランク番号の後にランク順で表示されます。これらは結果の順序指定 --[no]order_results フラグの影響を受けません(結果の順序に関する注意事項をご覧ください)。

この形式には 2 つのバリエーションがあります。minrank は、ルートノードからそのノードまでの最短経路の長さに基づいて各ノードをランク付けします。「ルート」ノード(受信エッジがないノード)はランク 0、その後継ノードはランク 1 のようになります(通常どおり、エッジはターゲットからその前提条件、つまり依存するターゲットを指しています)。

maxrank は、ルートノードからそのノードまでの最長パスの長さに基づいて各ノードをランク付けします。ここでも、「roots」のランクは 0 で、他のすべてのノードのランクは前のノードの最大ランクよりも 1 大きいランクです。

サイクル内のすべてのノードは同じランクとみなされます。(ほとんどのグラフは非巡回ですが、単に BUILD ファイルに誤ったサイクルが含まれているために循環が発生します)。

これらの出力形式は、グラフの深さを検出するのに役立ちます。deps(x)rdeps(x)、または allpaths クエリの結果に使用する場合、ランク番号は、x からそのランクのノードまでの最短パス(minrank を使用)または最長パス(maxrank を使用)と等しくなります。maxrank を使用すると、ターゲットのビルドに必要なビルドステップの最長シーケンスを決定できます。

たとえば、--output minrank--output maxrank が指定されている場合、左側のグラフは右側の出力になります。

上位にランクイン
      minrank

      0 //c:c
      1 //b:b
      1 //a:a
      2 //b:b.cc
      2 //a:a.cc
      
      maxrank

      0 //c:c
      1 //b:b
      2 //a:a
      2 //b:b.cc
      3 //a:a.cc
      
--output location

label_kind と同様に、このオプションは結果の各ターゲットについて、ターゲットの種類とラベルを出力しますが、そのターゲットの場所を示す文字列が先頭に付加され、ファイル名と行番号が使用されます。形式は grep の出力のようになります。したがって、後者を解析できるツール(Emacs や vi など)は、クエリ出力を使用して一連の一致をステップ実行することもできます。これにより、Bazel クエリツールを依存関係グラフ対応の「BUILD ファイルの grep」として使用できます。

位置情報はターゲットの種類によって異なります(kind 演算子をご覧ください)。ルールについては、BUILD ファイル内のルールの宣言の場所が出力されます。ソースファイルの場合は、実際のファイルの 1 行目の場所が出力されます。生成されたファイルについては、そのファイルを生成したルールの場所が出力されます。(クエリ ツールには、生成されたファイルの実際の場所を見つけるのに十分な情報がありません。いずれの場合も、ビルドがまだ実行されていない場合は存在しない可能性があります)。

--output package

このオプションは、結果セット内のターゲットが属するすべてのパッケージの名前を出力します。名前は辞書順で出力されます。重複は除外されます。正式には、これは一連のラベル(package、target)からパッケージへの射影になります。

外部リポジトリのパッケージは @repo//foo/bar の形式になりますが、メイン リポジトリのパッケージは foo/bar の形式になります。

この出力オプションを deps(...) クエリと組み合わせて使用すると、特定のターゲット セットをビルドするためにチェックアウトする必要があるパッケージのセットを検索できます。

結果のグラフを表示する

--output graph

このオプションを使用すると、クエリ結果が一般的な AT&T GraphViz 形式の有向グラフとして出力されます。通常、結果は .png.svg などのファイルに保存されます。(dot プログラムがワークステーションにインストールされていない場合は、sudo apt-get install graphviz コマンドを使用してインストールできます)。呼び出し例については、以下のサンプル セクションをご覧ください。

この出力形式は、allpathsdeps、または rdeps クエリで特に有用です。これらのクエリには、--output label などの線形形式でレンダリングすると簡単に可視化できない一連のパスが結果に含まれます。

デフォルトでは、グラフは因数分解形式でレンダリングされます。つまり、トポロジ的に同等のノードは、複数のラベルを持つ 1 つのノードにマージされます。一般的な結果グラフには繰り返しの多いパターンが含まれるため、グラフはよりコンパクトになり、読みやすくなります。たとえば、java_library ルールは、すべて同じ genrule で生成された何百もの Java ソースファイルに依存する可能性があります。因数分解グラフでは、これらのファイルはすべて 1 つのノードで表されます。この動作は、--nograph:factored オプションで無効にできます。

--graph:node_limit n

このオプションは、出力内のグラフノードのラベル文字列の最大長を指定します。それより長いラベルは切り捨てられます。-1 に設定すると、切り捨てが無効になります。グラフは通常、因数分解された形式で出力されるため、ノードラベルが非常に長くなることがあります。GraphViz は、このオプションのデフォルト値である 1, 024 文字を超えるラベルを処理できません。--output=graph が使用されている場合を除き、このオプションは無効です。

--[no]graph:factored

デフォルトでは、上記で説明されているように、グラフは因数分解されて表示されます。--nograph:factored を指定すると、因数分解せずにグラフが出力されます。このため、GraphViz を使用した可視化は実用的ではありませんが、シンプルな形式のほうが他のツール(grep など)による処理が容易になる場合があります。--output=graph が使用されている場合を除き、このオプションは無効です。

XML

--output xml

このオプションを使用すると、結果のターゲットが XML 形式で出力されます。出力は次のような XML ヘッダーで始まります。

  <?xml version="1.0" encoding="UTF-8"?>
  <query version="2">

その後、結果グラフの各ターゲットの XML 要素をトポロジ順に(順序付けられていない結果がリクエストされない限り)続き、終了で終了します。

</query>

file という種類のターゲットに対してシンプルなエントリが出力されます。

  <source-file name='//foo:foo_main.cc' .../>
  <generated-file name='//foo:libfoo.so' .../>

ただし、ルールの場合、XML は構造化されており、ルールの BUILD ファイルで値を明示的に指定していない属性を含め、ルールのすべての属性の定義が含まれています。

さらに、結果には rule-input 要素と rule-output 要素が含まれているため、依存関係グラフのトポロジを再構築できます。たとえば、srcs 属性の要素が前方依存関係(前提条件)であり、outs 属性のコンテンツが後方依存関係(コンシューマ)であることを把握する必要はありません。

--noimplicit_deps が指定されている場合、暗黙的な依存関係rule-input 要素が抑制されます。

  <rule class='cc_binary rule' name='//foo:foo' ...>
    <list name='srcs'>
      <label value='//foo:foo_main.cc'/>
      <label value='//foo:bar.cc'/>
      ...
    </list>
    <list name='deps'>
      <label value='//common:common'/>
      <label value='//collections:collections'/>
      ...
    </list>
    <list name='data'>
      ...
    </list>
    <int name='linkstatic' value='0'/>
    <int name='linkshared' value='0'/>
    <list name='licenses'/>
    <list name='distribs'>
      <distribution value="INTERNAL" />
    </list>
    <rule-input name="//common:common" />
    <rule-input name="//collections:collections" />
    <rule-input name="//foo:foo_main.cc" />
    <rule-input name="//foo:bar.cc" />
    ...
  </rule>

ターゲットのすべての XML 要素には、name 属性(値がターゲットのラベル)と location 属性(値が --output location によって出力されるターゲットの場所)が含まれています。

--[no]xml:line_numbers

デフォルトでは、XML 出力に表示される場所に行番号が含まれています。--noxml:line_numbers を指定すると、行番号が出力されません。

--[no]xml:default_values

デフォルトでは、値がその種類の属性のデフォルト値であるルール属性は XML 出力に含まれません(たとえば、BUILD ファイルで指定されていない場合や、デフォルト値が明示的に指定されている場合)。このオプションを使用すると、そのような属性値が XML 出力に含まれます。

正規表現

クエリ言語の正規表現は Java 正規表現ライブラリを使用するため、java.util.regex.Pattern の完全な構文を使用できます。

外部リポジトリを使用したクエリ

ビルドが外部リポジトリのルールに依存している場合、クエリ結果にはこれらの依存関係が含まれます。たとえば、//foo:bar@other-repo//baz:lib に依存している場合、bazel query 'deps(//foo:bar)'@other-repo//baz:lib を依存関係としてリストします。