cquery
は query
のバリエーションで、select()
とビルドオプションがビルドグラフに与える影響を正しく処理します。
これは、Bazel の分析フェーズの結果を実行することで実現されます。このフェーズでは、これらの効果が統合されます。一方、query
は、オプションが評価される前に、Bazel の読み込みフェーズの結果を実行します。
次に例を示します。
$ cat > tree/BUILD <<EOF sh_library( name = "ash", deps = select({ ":excelsior": [":manna-ash"], ":americana": [":white-ash"], "//conditions:default": [":common-ash"], }), ) sh_library(name = "manna-ash") sh_library(name = "white-ash") sh_library(name = "common-ash") config_setting( name = "excelsior", values = {"define": "species=excelsior"}, ) config_setting( name = "americana", values = {"define": "species=americana"}, ) EOF
# Traditional query: query doesn't know which select() branch you will choose, # so it conservatively lists all of possible choices, including all used config_settings. $ bazel query "deps(//tree:ash)" --noimplicit_deps //tree:americana //tree:ash //tree:common-ash //tree:excelsior //tree:manna-ash //tree:white-ash # cquery: cquery lets you set build options at the command line and chooses # the exact dependencies that implies (and also the config_setting targets). $ bazel cquery "deps(//tree:ash)" --define species=excelsior --noimplicit_deps //tree:ash (9f87702) //tree:manna-ash (9f87702) //tree:americana (9f87702) //tree:excelsior (9f87702)
各結果には、ターゲットがビルドされた構成の一意の識別子 (9f87702)
が含まれています。
cquery
は構成されたターゲット グラフ上で実行されるため、ビルドアクションなどのアーティファクトに関する分析情報は得られません。また、test_suite
ルールは構成されたターゲットではないため、アクセスできません。前者については、aquery
をご覧ください。
基本的な構文
簡単な cquery
呼び出しは次のようになります。
bazel cquery "function(//target)"
クエリ式 "function(//target)"
は次のとおりです。
function(...)
は、ターゲットで実行する関数です。cquery
は、query
のほとんどのfunctionsと、いくつかの新しい関数をサポートしています。//target
は、関数に渡される式です。この例では、式は単純なターゲットです。ただし、クエリ言語では関数のネストも可能です。例については、クエリガイドをご覧ください。
cquery
では、読み込みと分析フェーズを実行するターゲットが必要です。特に指定しない限り、cquery
はクエリ式にリストされているターゲットを解析します。トップレベルのビルド ターゲットの依存関係をクエリするには、--universe_scope
をご覧ください。
構成
次の行をご覧ください。
//tree:ash (9f87702)
は、//tree:ash
が ID 9f87702
の構成でビルドされたことを意味します。ほとんどのターゲットでは、これは構成を定義するビルドオプション値のオペーク ハッシュです。
構成の完全な内容を表示するには、次のコマンドを実行します。
$ bazel config 9f87702
9f87702
は完全な ID の接頭辞です。これは、完全な ID が SHA-256 ハッシュであり、長くて追跡しにくいためです。cquery
は、Git の短いハッシュと同様に、完全な ID の有効な接頭辞を認識します。完全な ID を表示するには、$ bazel config
を実行します。
ターゲット パターンの評価
//foo
は、cquery
と query
で意味が異なります。これは、cquery
が構成済みのターゲットを評価し、ビルドグラフに複数の構成済みバージョンの //foo
が存在する可能性があるためです。
cquery
の場合、クエリ式のターゲット パターンは、そのパターンに一致するラベルを持つ構成済みのすべてのターゲットに評価されます。出力は確定的ですが、cquery
はコアクエリの順序付け契約を超えて順序付けを保証しません。
これにより、query
の場合よりもクエリ式の結果が微妙になります。たとえば、次のようにすると複数の結果が生成されます。
# Analyzes //foo in the target configuration, but also analyzes # //genrule_with_foo_as_tool which depends on an exec-configured # //foo. So there are two configured target instances of //foo in # the build graph. $ bazel cquery //foo --universe_scope=//foo,//genrule_with_foo_as_tool //foo (9f87702) //foo (exec)
クエリ対象のインスタンスを正確に宣言する場合は、config
関数を使用します。
ターゲット パターンの詳細については、query
のターゲット パターンのドキュメントをご覧ください。
関数
query
でサポートされている関数のセットのうち、cquery
は visible
、siblings
、buildfiles
、tests
を除くすべての関数をサポートしています。
cquery
には、次の新しい関数も導入されています。
config
expr ::= config(expr, word)
config
オペレーターは、最初の引数で指定されたラベルと、2 番目の引数で指定された構成で構成されたターゲットを検索しようとします。
2 番目の引数の有効な値は、null
またはカスタム構成ハッシュです。ハッシュは $
bazel config
または前の cquery
の出力から取得できます。
例:
$ bazel cquery "config(//bar, 3732cc8)" --universe_scope=//foo
$ bazel cquery "deps(//foo)" //bar (exec) //baz (exec) $ bazel cquery "config(//baz, 3732cc8)"
指定された構成で最初の引数のすべての結果が見つからない場合、見つかった結果のみが返されます。指定された構成で結果が見つからない場合は、クエリは失敗します。
オプション
ビルド オプション
cquery
は通常の Bazel ビルドで実行されるため、ビルド中に使用可能なオプションのセットを継承します。
cquery オプションの使用
--universe_scope
(カンマ区切りのリスト)
多くの場合、構成されたターゲットの依存関係は遷移を経て、構成が依存関係と異なる原因となります。このフラグを使用すると、ターゲットが別のターゲットの依存関係または伝播依存関係としてビルドされているかのようにターゲットをクエリできます。次に例を示します。
# x/BUILD genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_binary( name = "tool", srcs = ["tool.cpp"], )
Genrules は実行構成でツールを構成するため、次のクエリでは次の出力が生成されます。
クエリ | ターゲット作成 | 出力 |
---|---|---|
bazel cquery "//x:tool" | //x:tool | //x:tool(targetconfig) |
bazel cquery "//x:tool" --universe_scope="//x:my_gen" | //x:my_gen | //x:tool(execconfig) |
このフラグが設定されている場合、その内容がビルドされます。設定されていない場合、クエリ式で指定されたすべてのターゲットがビルドされます。ビルドされたターゲットの推移閉包がクエリのユニバースとして使用されます。どちらの場合も、ビルドするターゲットは最上位でビルド可能である必要があります(つまり、最上位オプションと互換性がある必要があります)。cquery
は、これらのトップレベル ターゲットの推移閉包で結果を返します。
クエリ式のトップレベルですべてのターゲットを作成できる場合でも、そうしないほうがよい場合があります。たとえば、--universe_scope
を明示的に設定すると、不要な構成でターゲットが複数回作成されるのを防ぐことができます。また、ターゲットのどの構成バージョンを探しているかを指定することもできます(現在のところ、他の方法で完全に指定することはできません)。クエリ式が deps(//foo)
よりも複雑な場合は、このフラグを設定する必要があります。
--implicit_deps
(ブール値、デフォルト: True)
このフラグを false に設定すると、BUILD ファイルで明示的に設定されていない結果と、Bazel によって他の場所で設定された結果がすべて除外されます。これには、解決済みのツールチェーンのフィルタリングも含まれます。
--tool_deps
(ブール値、デフォルト: True)
このフラグを false に設定すると、クエリされたターゲットからそのターゲットへのパスが、ターゲット構成とターゲット以外の構成の間の遷移を横切るすべての構成されたターゲットが除外されます。クエリ対象のターゲットがターゲット構成にある場合、--notool_deps
を設定すると、ターゲット構成にあるターゲットのみが返されます。クエリされたターゲットがターゲット以外の構成にある場合、--notool_deps
を設定すると、ターゲット以外の構成のターゲットのみが返されます。通常、この設定は解決された toolchain のフィルタリングには影響しません。
--include_aspects
(ブール値、デフォルト: True)
アスペクトによって追加された依存関係を含めます。
このフラグが無効になっている場合、X がアスペクトを介してのみ Y に依存している場合、cquery somepath(X, Y)
と cquery deps(X) | grep 'Y'
は Y を省略します。
出力形式
デフォルトでは、cquery はラベルと構成ペアの依存関係順のリストに結果を出力します。結果を公開する方法は他にもあります。
遷移
--transitions=lite --transitions=full
構成遷移は、最上位ターゲットとは異なる構成で最上位ターゲットの下にターゲットをビルドするために使用されます。
たとえば、ターゲットは tools
属性のすべての依存関係に exec 構成への移行を適用できます。これを属性遷移と呼びます。ルールは、独自の構成に遷移を適用することもできます。これはルールクラス遷移と呼ばれます。この出力形式では、これらの遷移に関する情報(タイプやビルドオプションへの影響など)が出力されます。
この出力形式は、デフォルトで NONE
に設定されている --transitions
フラグによってトリガーされます。FULL
モードまたは LITE
モードに設定できます。FULL
モードは、ルールクラスの遷移と属性の遷移に関する情報(遷移前後のオプションの詳細な差分など)を出力します。LITE
モードでは、オプションの差分なしで同じ情報が出力されます。
プロトコル メッセージの出力
--output=proto
このオプションを使用すると、生成されたターゲットがバイナリ プロトコル バッファ形式で出力されます。プロトコル バッファの定義は、src/main/protobuf/analysis_v2.proto にあります。
CqueryResult
は、cquery の結果を含む最上位レベルのメッセージです。ConfiguredTarget
メッセージのリストと Configuration
メッセージのリストがあります。各 ConfiguredTarget
には、対応する Configuration
メッセージの id
フィールドの値と同じ値の configuration_id
があります。
--[no]proto:include_configurations
デフォルトでは、cquery の結果は、構成された各ターゲットの一部として構成情報を返します。この情報を省略し、クエリの proto 出力とまったく同じ形式の proto 出力を取得する場合は、このフラグを false に設定します。
proto 出力関連のオプションについては、クエリの proto 出力ドキュメントをご覧ください。
グラフ出力
--output=graph
このオプションを使用すると、出力が Graphviz 互換の .dot ファイルとして生成されます。詳細については、query
のグラフ出力ドキュメントをご覧ください。cquery
は --graph:node_limit
と --graph:factored
もサポートしています。
出力ファイル
--output=files
このオプションを使用すると、bazel build
呼び出しの最後に出力されるリストと同様に、クエリに一致する各ターゲットによって生成された出力ファイルのリストが出力されます。出力には、--output_groups
フラグによって決定される、リクエストされた出力グループでアドバタイズされたファイルのみが含まれます。ソースファイルは含まれています。
この出力形式で出力されるパスはすべて、bazel info execution_root
で取得できる execroot を基準としています。bazel-out
便利なシンボリック リンクが存在する場合、メイン リポジトリ内のファイルへのパスもワークスペース ディレクトリを基準に解決されます。
Starlark を使用した出力形式の定義
--output=starlark
この出力形式では、クエリ結果で構成されたターゲットごとに Starlark 関数を呼び出し、呼び出しによって返された値を出力します。--starlark:file
フラグは、単一のパラメータ target
を持つ format
という名前の関数を定義する Starlark ファイルの場所を指定します。この関数は、クエリ結果の各ターゲットに対して呼び出されます。または、便宜上、--starlark:expr
フラグを使用して、def format(target): return expr
として宣言された関数の本文のみを指定することもできます。
Starlark 言語「cquery」方言
cquery Starlark 環境は、BUILD ファイルや .bzl ファイルとは異なります。これには、すべてのコア Starlark の組み込み定数と関数に加えて、後述する cquery 固有のものがいくつか含まれています。ただし、glob
、native
、rule
などは含まれません。また、load ステートメントはサポートされていません。
build_options(target)
build_options(target)
は、キーがビルドオプション ID(構成を参照)で、値が Starlark 値のマップを返します。値が有効な Starlark 値ではないビルドオプションは、このマップから除外されます。
ターゲットが入力ファイルの場合、入力ファイル ターゲットの構成が null であるため、build_options(target)
は None を返します。
providers(target)
providers(target)
は、キーがプロバイダの名前("DefaultInfo"
など)で、値が Starlark 値のマップを返します。値が有効な Starlark 値ではないプロバイダは、このマップから除外されます。
例
//foo
によって生成されたすべてのファイルのベース名をスペース区切りで出力します。
bazel cquery //foo --output=starlark \ --starlark:expr="' '.join([f.basename for f in target.files.to_list()])"
//bar
とそのサブパッケージのルール ターゲットによって生成されたすべてのファイルのパスのスペース区切りリストを出力します。
bazel cquery 'kind(rule, //bar/...)' --output=starlark \ --starlark:expr="' '.join([f.path for f in target.files.to_list()])"
//foo
によって登録されたすべてのアクションの頭文字のリストを表示します。
bazel cquery //foo --output=starlark \ --starlark:expr="[a.mnemonic for a in target.actions]"
cc_library
//baz
によって登録されたコンパイル出力のリストを出力します。
bazel cquery //baz --output=starlark \ --starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"
//foo
のビルド時に、コマンドライン オプション --javacopt
の値を出力します。
bazel cquery //foo --output=starlark \ --starlark:expr="build_options(target)['//command_line_option:javacopt']"
出力が 1 つのみになるように、各ターゲットのラベルを出力します。この例では、ファイルで定義された Starlark 関数を使用します。
$ cat example.cquery def has_one_output(target): return len(target.files.to_list()) == 1 def format(target): if has_one_output(target): return target.label else: return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
厳密に Python 3 である各ターゲットのラベルを出力します。この例では、ファイルで定義された Starlark 関数を使用します。
$ cat example.cquery def format(target): p = providers(target) py_info = p.get("PyInfo") if py_info and py_info.has_py3_only_sources: return target.label else: return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
ユーザー定義のプロバイダから値を抽出します。
$ cat some_package/my_rule.bzl MyRuleInfo = provider(fields={"color": "the name of a color"}) def _my_rule_impl(ctx): ... return [MyRuleInfo(color="red")] my_rule = rule( implementation = _my_rule_impl, attrs = {...}, ) $ cat example.cquery def format(target): p = providers(target) my_rule_info = p.get("//some_package:my_rule.bzl%MyRuleInfo'") if my_rule_info: return my_rule_info.color return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
cquery と query
cquery
と query
は互いに補完し合い、それぞれ異なるニッチで優れています。どちらが適しているかを判断する際は、次の点を考慮してください。
cquery
は特定のselect()
ブランチに従って、作成する正確なグラフをモデル化します。query
は、ビルドが選択するブランチを認識しないため、すべてのブランチを含めて過剰近似します。cquery
の精度を高めるには、query
よりも多くのグラフを構築する必要があります。具体的には、cquery
は構成されたターゲットを評価し、query
はターゲットのみを評価します。この場合、時間とメモリの使用量が増えます。cquery
によるクエリ言語の解釈は、query
では回避されるあいまいさを導入します。たとえば、"//foo"
が 2 つの構成に存在する場合、cquery "deps(//foo)"
はどちらを使用する必要がありますか。config
関数を使用すると、この作業を簡単に行うことができます。- 新しいツールである
cquery
は、特定のユースケースをサポートしていません。詳しくは、既知の問題をご覧ください。
既知の問題
cquery
が「ビルド」するすべてのターゲットは同じ構成にする必要があります。
cquery
は、クエリを評価する前に、ビルドアクションが実行される直前にビルドをトリガーします。ターゲットの「ビルド」は、デフォルトではクエリ式に表示されるすべてのラベルから選択されます(これは --universe_scope
でオーバーライドできます)。これらのターゲットは同じ構成にする必要があります。
これらは通常、トップレベルの「ターゲット」構成を共有しますが、ルールは受信エッジ遷移で独自の構成を変更できます。これが cquery
の限界です。
回避策: 可能であれば、--universe_scope
をより厳格なスコープに設定します。次に例を示します。
# This command attempts to build the transitive closures of both //foo and # //bar. //bar uses an incoming edge transition to change its --cpu flag. $ bazel cquery 'somepath(//foo, //bar)' ERROR: Error doing post analysis query: Top-level targets //foo and //bar have different configurations (top-level targets with different configurations is not supported) # This command only builds the transitive closure of //foo, under which # //bar should exist in the correct configuration. $ bazel cquery 'somepath(//foo, //bar)' --universe_scope=//foo
--output=xml
はサポートされていません。
非決定的な出力。
cquery
は、以前のコマンドからビルドグラフを自動的に消去しないため、過去のクエリの結果を取得する傾向があります。たとえば、genquery
は tools
属性に exec 遷移を適用します。つまり、exec 構成でツールを構成します。
移行の影響が残っている状況は以下のとおりです。
$ cat > foo/BUILD <<<EOF genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_library( name = "tool", ) EOF $ bazel cquery "//foo:tool" tool(target_config) $ bazel cquery "deps(//foo:my_gen)" my_gen (target_config) tool (exec_config) ... $ bazel cquery "//foo:tool" tool(exec_config)
回避策: 構成済みのターゲットの再分析を強制的に行うように起動オプションを変更します。たとえば、ビルドコマンドに --test_arg=<whatever>
を追加します。
トラブルシューティング
再帰ターゲット パターン(/...
)
以下の場合は、
$ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, //foo/...)" ERROR: Error doing post analysis query: Evaluation failed: Unable to load package '[foo]' because package is not in scope. Check that all target patterns in query expression are within the --universe_scope of this query.
これは、--universe_scope=//foo:app
に含まれているにもかかわらず、パッケージ //foo
がスコープ外であると誤って示唆しています。これは cquery
の設計上の制限によるものです。回避策として、ユニバース スコープに //foo/...
を明示的に含めます。
$ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"
それでも機能しない場合は(たとえば、//foo/...
の一部のタゲが選択したビルドフラグでビルドできない場合など)、前処理クエリを使用してパターンを手動で展開し、構成パッケージにします。
# Replace "//foo/..." with a subshell query call (not cquery!) outputting each package, piped into # a sed call converting "<pkg>" to "//<pkg>:*", piped into a "+"-delimited line merge. # Output looks like "//foo:*+//foo/bar:*+//foo/baz". # $ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, $(bazel query //foo/... --output=package | sed -e 's/^/\/\//' -e 's/$/:*/' | paste -sd "+" -))"