Bazel クエリ リファレンス

問題を報告 ソースを表示

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

実際の使用例については、Bazel クエリの使用方法をご覧ください。

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

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

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

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

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

構成可能なクエリ

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

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

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

//foo ツリーが //bar/baz に依存する理由経路を表示する:

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

すべての foo テストで、foo_bin ターゲットが依存していない C++ ライブラリはどれですか?

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

トークン: 語彙構文

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

  • キーワードlet など)。キーワードはこの言語の予約語であり、それぞれ以下で説明します。すべてのキーワードは次のとおりです。

  • 単語: 「foo/...」、「.*test rule」、「//bar/baz:all」など。文字シーケンスが「引用符で囲まれている」(一重引用符「」で始まり、二重引用符で終わる)場合、それは単語です。文字シーケンスが引用符で囲まれていない場合でも、単語として解析される場合があります。引用符で囲まれていない単語は、アルファベット A ~ Za ~ 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(設定): ターゲットの部分的な順序は重要ではありません。
  • グラフ: ターゲットの部分的な順序が重要です。

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

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

クエリ言語で使用されるアルゴリズムは、非巡回グラフでの使用を想定していますが、サイクルに対して堅牢です。サイクルの処理方法については詳細は示されていないので、これに依存しないでください。

暗黙的な依存関係

Bazel では、BUILD ファイルで明示的に定義されているビルド依存関係に加えて、暗黙的な依存関係をルールに追加します。たとえば、すべての Java ルールは暗黙的に JavaBuilder に依存します。暗黙的な依存関係は、$ で始まる属性を使用して確立され、BUILD ファイルでオーバーライドできません。

デフォルトごとの bazel query では、クエリ結果の計算時に暗黙的な依存関係が考慮されます。この動作は --[no]implicit_deps オプションで変更できます。クエリでは構成が考慮されないため、潜在的なツールチェーンは考慮されません。

健全性

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

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

グラフの順序の保持

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

ただし、すべての演算子の順序は保持されますが、集合演算などの一部の演算では、独自の順序の制約は適用されません。次の式について考えてみましょう。

deps(x) union y

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

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

Sky のクエリ

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

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

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

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

Sky Query モードは、--universe_scope または --infer_universe_scope--order_output=no の 2 つのフラグを渡すことで有効になります。--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 つの形式があります。intersect などの名詞形式と、^ などの記号形式があります。どちらの形式も同等です。シンボリック形式の方が手早く入力できます。(わかりやすくするために、このページの残りの部分では名詞形式を使用します)。

たとえば、

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 ...) 演算子は、空白(カンマなし)で区切られた 0 個以上のターゲット パターンの和集合を計算します。

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) の省略形ですが、cat 以外のシェルコマンド(上記の awk コマンドなど)も使用できます。

関数

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) 演算子は、最大 k 個のターゲットを引数セット x から任意に選択し、それらのターゲットのみを含むセットを評価します。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)

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

expr ::= kind(word, expr)

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

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

コード ターゲット 種類
        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 を使用してください。

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

expr ::= filter(word, expr)

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

最初の引数 pattern は、ターゲット名に対する正規表現を含む単語です。filter 式は、xinput セットのメンバーであり、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) 演算子のもう 1 つの一般的な使用方法は、特定のファイルを名前または拡張子でフィルタリングすることです。たとえば、

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))

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

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

data 属性に 1 つ以上の値を指定する //foo 依存関係の中からすべてのルールを選択します(//: のため、すべてのラベルの長さは 3 文字以上です)。

リスト型属性で特定の value を持つ //foo 依存関係の中からすべてのルールを選択するには、次のコマンドを使用します。

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

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

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

expr ::= visible(expr, expr)

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

最初の引数 predicate は、出力内のすべてのターゲットに対して参照できる必要があるターゲットのセットです。visible 式は、x がセット input のメンバーであり、predicate のすべてのターゲットの yy から参照できるように、すべてのターゲット x を含むセットと評価します。x次に例を示します。

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

これにより、公開設定の制限に違反せずに //foo が依存できるパッケージ //bar 内のターゲットがすべて選択されます。

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

expr ::= labels(word, expr)

labels(attr_name, inputs) 演算子は、セット inputs の一部のルールで、タイプ「ラベル」または「ラベルのリスト」の属性 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 ルールによって直接的または間接的に参照される他のパッケージに属するテストが含まれる場合があります。

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

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_name または generator_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 と同様に、minrankmaxrank の出力形式では、結果のグラフに各ターゲットのラベルが出力されますが、トポロジ順に表示されるのではなく、ランク番号が先行するランク順に表示されます。これらは、結果の順序付け --[no]order_results フラグの影響を受けません(結果の順序に関する注意事項をご覧ください)。

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

maxrank は、ルートノードからルートノードまでの最長パスの長さを基準に各ノードをランク付けします。ここでも、「ルート」のランクは 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 クエリツールを依存関係グラフ対応の「grep for BUILD ファイル」として使用できます。

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

--output package

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

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

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

結果のグラフを表示する

--output graph

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

この出力形式は、allpathsdepsrdeps クエリで特に役立ちます。--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 の完全な構文を使用できます。

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

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

外部リポジトリ自体は、ビルドの依存関係ではありません。つまり、上記の例では、//external:other-repo は依存関係ではありません。ただし、//external パッケージのメンバーとしてクエリすることはできます。次に例を示します。

  # Querying over all members of //external returns the repository.
  bazel query 'kind(http_archive, //external:*)'
  //external:other-repo

  # ...but the repository is not a dependency.
  bazel query 'kind(http_archive, deps(//foo:bar))'
  INFO: Empty results