aquery
指令可讓您查詢建構圖中的動作。它會在之後分析設定的目標圖表上執行,並顯示動作、成果及其關係的相關資訊。
如果您想瞭解從已設定的目標圖表產生的動作/構件屬性,aquery
就很實用。舉例來說,實際指令會執行
及其輸入/輸出內容/記憶法
這項工具接受多個指令列選項。值得注意的是,aquery 指令會在一般 Bazel 建構作業上執行,並繼承建構期間可用的選項組合。
它支援傳統 query
可用的函式,但 siblings
、buildfiles
和 tests
則不支援。
aquery
輸出內容範例 (不含詳細資料):
$ bazel aquery 'deps(//some:label)' action 'Writing file some_file_name' Mnemonic: ... Target: ... Configuration: ... ActionKey: ... Inputs: [...] Outputs: [...]
基本語法
aquery
的語法簡單範例如下:
bazel aquery "aquery_function(function(//target))"
查詢運算式 (以引號括住) 包含下列項目:
# aquery examples: # Get the action graph generated while building //src/target_a $ bazel aquery '//src/target_a' # Get the action graph generated while building all dependencies of //src/target_a $ bazel aquery 'deps(//src/target_a)' # Get the action graph generated while building all dependencies of //src/target_a # whose inputs filenames match the regex ".*cpp". $ bazel aquery 'inputs(".*cpp", deps(//src/target_a))'
使用 aquery 函式
共有三個 aquery
函式:
inputs
:依輸入內容篩選動作。outputs
:依輸出內容篩選動作mnemonic
:依記憶法篩選動作
expr ::= inputs(word, expr)
inputs
運算子會傳回建構 expr
時產生的動作,其輸入檔案名稱會與 word
提供的規則運算式相符。
$ bazel aquery 'inputs(".*cpp", deps(//src/target_a))'
outputs
和 mnemonic
函式的語法相似。
您亦可結合函式以執行 AND 作業。例如:
$ bazel aquery 'mnemonic("Cpp.*", (inputs(".*cpp", inputs("foo.*", //src/target_a))))'
上述指令會找出與建構 //src/target_a
相關的所有動作,其記憶法與 "Cpp.*"
且輸入內容符合 ".*cpp"
和 "foo.*"
模式。
產生的語法錯誤示例:
$ bazel aquery 'deps(inputs(".*cpp", //src/target_a))' ERROR: aquery filter functions (inputs, outputs, mnemonic) produce actions, and therefore can't be the input of other function types: deps deps(inputs(".*cpp", //src/target_a))
選項
建構選項
aquery
會在一般 Bazel 建構作業上執行,因此會繼承建構期間可用的選項組合。
Aquery 選項
--output=(text|summary|proto|jsonproto|textproto), default=text
預設輸出格式 (text
) 是人類可讀的格式,請使用 proto
、textproto
或 jsonproto
來提供機器可讀的格式。proto 訊息為 analysis.ActionGraphContainer
。
--include_commandline, default=true
輸出內容包含動作指令列內容 (可能很大)。
--include_artifacts, default=true
輸出內容會包含動作輸入和輸出項目的名稱 (可能很大)。
--include_aspects, default=true
是否要在輸出內容中加入 Aspect 產生的動作。
--include_param_files, default=false
請附上指令中使用的參數檔案內容 (可能很大)。
--include_file_write_contents, default=false
加入 actions.write()
動作的檔案內容,以及 SourceSymlinkManifest
動作的資訊清單檔案內容。檔案內容會透過 --output=
xxxproto
傳回至 file_contents
欄位。使用 --output=text
時,輸出內容會包含 FileWriteContents: [<base64-encoded file contents>]
行
--skyframe_state, default=false
在不執行額外分析的情況下,從 Skyframe 轉儲動作圖。
其他工具和功能
針對 Skyframe 狀態執行查詢
Skyframe 是 Bazel 的評估和增量模型。在每個 Bazel 伺服器執行個體上,Skyframe 會儲存先前執行分析階段時建構的依附元件圖表。
在某些情況下,在 Skyframe 上查詢動作圖表會很有幫助。應用情境範例如下:
- 執行
bazel build //target_a
- 執行
bazel build //target_b
- 已產生檔案
foo.out
。
身為 Bazel 使用者,我想判斷 foo.out
是否透過建構 //target_a
或 //target_b
產生。
您可以執行 bazel aquery 'outputs("foo.out", //target_a)'
和 bazel aquery 'outputs("foo.out", //target_b)'
,找出負責建立 foo.out
的動作,進而找出目標。但是,先前建構的不同目標數量可能會大於 2,這使得執行多個 aquery
指令變得很麻煩。
您也可以改用 --skyframe_state
旗標:
# List all actions on Skyframe's action graph $ bazel aquery --output=proto --skyframe_state # or # List all actions on Skyframe's action graph, whose output matches "foo.out" $ bazel aquery --output=proto --skyframe_state 'outputs("foo.out")'
在 --skyframe_state
模式下,aquery
會擷取 Skyframe 在 Bazel 例項上保留的動作圖形內容,並視需要對其執行篩選,然後輸出內容,而無須重新執行分析階段。
特殊注意事項
輸出格式
--skyframe_state
目前僅適用於 --output=proto
和 --output=textproto
查詢運算式中未包含目標標籤
目前,--skyframe_state
會查詢 Skyframe 上存在的整個動作圖表,不論目標為何。在查詢中指定目標標籤和 --skyframe_state
會造成語法錯誤:
# WRONG: Target Included $ bazel aquery --output=proto --skyframe_state **//target_a** ERROR: Error while parsing '//target_a)': Specifying build target(s) [//target_a] with --skyframe_state is currently not supported. # WRONG: Target Included $ bazel aquery --output=proto --skyframe_state 'inputs(".*.java", **//target_a**)' ERROR: Error while parsing '//target_a)': Specifying build target(s) [//target_a] with --skyframe_state is currently not supported. # CORRECT: Without Target $ bazel aquery --output=proto --skyframe_state $ bazel aquery --output=proto --skyframe_state 'inputs(".*.java")'
比較 Aquery 輸出結果
您可以使用 aquery_differ
工具比較兩個不同 aquery 叫用作業的輸出內容。舉例來說,如果您對規則定義進行一些變更,並想驗證執行的命令列是否未變更,aquery_differ
是適當的工具。
您可以在 bazelbuild/bazel 存放區中找到這項工具。如要使用它,請將存放區複製到本機電腦。使用範例:
$ bazel run //tools/aquery_differ -- \ --before=/path/to/before.proto \ --after=/path/to/after.proto \ --input_type=proto \ --attrs=cmdline \ --attrs=inputs
上述指令會傳回 before
和 after
aquery 輸出結果之間的差異:哪些動作只出現在其中一個輸出結果,哪些動作在每個 aquery 輸出結果中具有不同的指令列/輸入內容,等等。執行上述指令的結果如下:
Aquery output 'after' change contains an action that generates the following outputs that aquery output 'before' change doesn't: ... /list of output files/ ... [cmdline] Difference in the action that generates the following output(s): /path/to/abc.out --- /path/to/before.proto +++ /path/to/after.proto @@ -1,3 +1,3 @@ ... /cmdline diff, in unified diff format/ ...
指令選項
--before, --after
:要比較的查詢輸出檔案
--input_type=(proto|text_proto), default=proto
:輸入檔案格式。支援 proto
和 textproto
aquery 輸出內容。
--attrs=(cmdline|inputs), default=cmdline
:要比較的動作屬性。
長寬比
切面可以相互套用。這些層面產生的動作的 aquery 輸出內容就會包含層面路徑,也就是套用至產生動作的目標的層面序列。
Aspect-on-Aspect 範例:
t0 ^ | <- a1 t1 ^ | <- a2 t2
讓 ti 成為規則 ri 的目標,該規則會將特徵 ai 套用至其依附元件。
假設 a2 套用至目標 t0 時會產生動作 X。針對動作 X,bazel aquery --include_aspects 'deps(//t2)'
的文字輸出內容會是:
action ... Mnemonic: ... Target: //my_pkg:t0 Configuration: ... AspectDescriptors: [//my_pkg:rule.bzl%**a2**(foo=...) -> //my_pkg:rule.bzl%**a1**(bar=...)] ...
這表示動作 X
是由套用至 a1(t0)
的 Aspect a2
產生,其中 a1(t0)
是對目標 t0
套用 Aspect a1
的結果。
每個 AspectDescriptor
的格式如下:
AspectClass([param=value,...])
AspectClass
可以是 Aspect 類別的名稱 (針對原生 Aspect) 或 bzl_file%aspect_name
(針對 Starlark Aspect)。AspectDescriptor
是按照依附元件圖表的頂端順序排序。
與 JSON 設定檔建立連結
雖然 aquery 會提供在建構中執行的動作相關資訊 (執行原因、輸入/輸出),但 JSON 設定檔會告知執行時間和執行時間長度。您可以透過共同分母 (動作的主要輸出內容) 結合這兩組資訊。
如要在 JSON 設定檔中加入動作的輸出內容,請使用 --experimental_include_primary_output --noslim_profile
產生設定檔。精簡設定檔不相容於包含主要輸出內容的情況。根據預設,aquery 會納入動作的主要輸出內容。
我們目前沒有提供標準工具來結合這兩個資料來源,但您應該可以根據上述資訊建立自己的指令碼。
已知問題
處理共用動作
有時動作會在設定的目標之間共用。
在執行階段,系統會簡單地將這些共用動作視為單一動作,並只執行一次。不過,aquery 會針對執行前、分析後的動作圖表運作,因此會將這些動作視為個別動作,且輸出成果的構件具有完全相同的 execPath
。因此,等效的構件會顯示為重複。
您可以在 GitHub 上查看 aquery 問題/已規劃功能的清單。
常見問題
即使輸入檔案的內容有所變更,ActionKey 仍會維持不變。
在 aquery 的內容中,ActionKey
是指從 ActionAnalysisMetadata#getKey 取得的 String
:
Returns a string encoding all of the significant behaviour of this Action that might affect the output. The general contract of `getKey` is this: if the work to be performed by the execution of this action changes, the key must change. ... Examples of changes that should affect the key are: - Changes to the BUILD file that materially affect the rule which gave rise to this Action. - Changes to the command-line options, environment, or other global configuration resources which affect the behaviour of this kind of Action (other than changes to the names of the input/output files, which are handled externally). - An upgrade to the build tools which changes the program logic of this kind of Action (typically this is achieved by incorporating a UUID into the key, which is changed each time the program logic of this action changes). Note the following exception: for actions that discover inputs, the key must change if any input names change or else action validation may falsely validate.
這會排除輸入檔案內容的變更,請勿與 RemoteCacheClient#ActionKey 混淆。
更新
如有任何問題/功能要求,請透過這個頁面回報問題。