動作圖查詢 (查詢)

aquery 指令可讓您在建構圖中查詢動作。它會依據分析後設定的目標圖表運作,並顯示動作、構件及其關係的相關資訊。

如果您對設定的目標圖表產生的動作/構件感興趣,aquery 是非常實用的工具。例如,實際的指令會執行及其輸入/輸出/助聽。

這項工具接受多個指令列選項。值得注意的是,查詢指令會在一般 Bazel 建構作業上執行,並繼承建構期間可用的一組選項。

其支援的函式組合也適用於傳統 query,但 siblingsbuildfilestests

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_function(...)aquery 專屬的函式。詳情請見下文
  • function(...):標準函式,與傳統 query 相同。
  • //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 函式有三個:

  • inputs:依輸入篩選動作。
  • outputs:依輸出篩選動作
  • mnemonic:按照記憶功能篩選動作

expr ::= inputs(word, expr)

inputs 運算子會傳回建構 expr 時產生的動作,這些動作的輸入檔案名稱與 word 提供的規則運算式相符。

$ bazel aquery 'inputs(".*cpp", deps(//src/target_a))'

outputsmnemonic 函式共用類似的語法。

您也可以結合函式來達到 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) 為使用者可理解的格式,請將 prototextprotojsonproto 設為機器可讀取的格式。proto 訊息為 analysis.ActionGraphContainer

--include_commandline, default=true

輸出內容中包含動作指令列的內容 (可能非常大)。

--include_artifacts, default=true

在輸出內容中加入動作輸入和輸出的名稱 (可能非常大)。

--include_aspects, default=true

是否要在輸出內容中納入由長寬比產生的動作。

--include_param_files, default=false

加入指令中使用的參數檔案內容 (可能非常大)。

--include_file_write_contents, default=false

加入 actions.write() 動作的檔案內容,以及 SourceSymlinkManifest 動作的資訊清單檔案內容。系統會在 file_contents 欄位中傳回 --output=xxxproto 的檔案內容。如果使用 --output=text,輸出結果會包含 FileWriteContents: [<base64-encoded file contents>]

--skyframe_state, default=false

如未執行額外分析,而是從 SkyFrame 傾印動作圖。

其他工具和功能

針對 SkyFrame 狀態進行查詢

SkyFrame 是 Bazel 的評估和增量模型。在 Bazel 伺服器的每個執行個體上,SkyFrame 會儲存先前執行分析階段而建構的依附元件圖表。

在某些情況下,查詢 SkyFrame 的動作圖表會很有用。用途範例如下:

  1. 執行 bazel build //target_a
  2. 執行 bazel build //target_b
  3. 已產生檔案「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_differ 工具比較兩個不同查詢叫用的輸出內容。例如,當您對規則定義進行一些變更,並想要確認執行的指令列並未改變時。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

上述指令會傳回查詢輸出 beforeafter 之間的差異:哪些動作出現在一個查詢中,其他動作則否。其他動作的每個查詢輸出結果中,都有不同的指令列/輸入內容...)。執行上述指令的結果如下:

  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:輸入檔案的格式。支援 prototextproto 查詢輸出內容。

--attrs=(cmdline|inputs), default=cmdline:要比較的動作屬性。

長寬比

長寬比可以互相套用。這些規範所產生的動作的查詢輸出會接著包含顯示路徑,也就是套用至產生動作的目標所套用的各切面序列。

長寬比示例:

  t0
  ^
  | <- a1
  t1
  ^
  | <- a2
  t2

讓「i」ii為規則規則的目標,這會將「i」i部分套用至其依附元件。

假設將 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)a2 產生,其中 a1(t0) 是套用至目標 t0 的結果 a1 的結果。

每個 AspectDescriptor 都具有以下格式:

  AspectClass([param=value,...])

AspectClass 可以是 Aspect 類別 (適用於原生規格) 或 bzl_file%aspect_name (如 Starlark Aspects) 的名稱。AspectDescriptor 會依依附元件圖表的邏輯順序排序。

使用 JSON 設定檔連結

查詢提供了在建構作業中執行動作的相關資訊 (執行原因和輸入/輸出),JSON 設定檔也會告知執行作業的時間和持續時間。您可以透過通用分母來結合這 2 組資訊,也就是動作的主要輸出內容。

如要在 JSON 設定檔中加入動作的輸出內容,請使用 --experimental_include_primary_output --noexperimental_slim_json_profile 產生設定檔。Slim 設定檔與主要輸出內容不相容。根據預設,查詢會包含動作的主要輸出內容。

我們目前並未提供合併這 2 個資料來源的標準工具,但您應能使用上述資訊來建構自己的指令碼。

已知問題

處理共用動作

有時動作會在設定的目標之間共用

在執行階段,這些共用動作只會視為一次,且只會執行一次。不過,查詢會在執行前、分析後動作圖上運作,因此會將其視為獨立動作,而輸出 Artifact 的輸出 execPath 完全相同。因此,對等的 Artifacts 看起來會重複。

如需查詢問題/預定功能清單,請前往 GitHub

常見問題

即使輸入檔案的內容有所變更,ActionKey 仍將保持不變。

在查詢的內容中,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 混淆。

更新

如有任何問題/功能要求,請在這裡回報問題。