可設定的查詢 (cquery)

回報問題 查看原始碼 夜間 7.2 7.1 7.0 6.5 6.4

cqueryquery 的變化版本,可正確處理 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)

每筆結果都包含一個專屬 ID (9f87702) 設定 建構容器

因為 cquery 執行於設定的目標圖表。沒有深入分析 轉換為構件,例如建構動作和 test_suite 存取權 因為這類系統並非設定目標如果是前者,請參閱 aquery

基本語法

簡單的 cquery 呼叫如下所示:

bazel cquery "function(//target)"

查詢運算式 "function(//target)" 包含下列內容:

  • function(...) 是要在目標上執行的函式。cquery 支援多數 「query」的函式,再加上 有幾個新問題
  • //target 是提供給函式的運算式。在這個範例中, 運算式是簡單的目標但查詢語言也能建立函式的巢狀結構。 如需範例,請參閱查詢指南

cquery 要求目標必須經過載入與分析執行 階段除非另有指定,否則 cquery 會剖析 查詢運算式。查看「--universe_scope」 ,查詢頂層建構目標的依附元件。

設定

線條:

//tree:ash (9f87702)

代表 //tree:ash 是在 ID 為 9f87702 的設定中建構。大多數 此為不透明的雜湊值,定義 此外還會從 0 自動調整資源配置 您完全不必調整資源調度設定

如要查看設定的完整內容,請執行:

$ bazel config 9f87702

9f87702 是完整 ID 的前置字串。這是因為完整的 ID SHA-256 雜湊,這類很冗長且難以追蹤。cquery 瞭解 開頭,例如 Git 短雜湊。 如要查看完整 ID,請執行 $ bazel config

目標模式評估

//foocquery 的意義與 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 則支援除了 allrdepsbuildfiles, rbuildfiles, siblings, testsvisible

cquery 也會提供下列新函式:

config

expr ::= config(expr, word)

config 運算子會嘗試尋找已設定的目標 由第一個引數和 第二個引數。

第二個引數的有效值為 null 或 「自訂設定雜湊」。雜湊可以從 $ bazel configcquery 先前的輸出內容中擷取。

範例:

$ 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 會在 exec 設定 因此,下列查詢會產生下列輸出內容:

查詢 已建構的目標 輸出
bazel cquery "//x:tool" //x:tool //x:tool(targetconfig)
bazel cquery "//x:tool"--universe_scope=&quot;//x:my_gen&quot; //x:my_gen //x:tool(execconfig)

如果設定此標記,則會建構其內容。如未設定,所有指定 系統會改為建構解除 會使用建構的目標做為查詢的宇宙。無論您選擇哪種方式,目標 必須能在頂層建構元件 (也就是與頂層元件相容) 選項)。cquery 會傳回這些項目的遞移性關閉結果 頂層指定目標

即使可以建立所有目標在頂端的查詢運算式中 否則可能會有所助益。例如,如果您明確設定 --universe_scope 可防止多次建立目標: 載入 Google Cloud 的某些設定這項工具也能協助您 才能觸及理想目標對象 (因為目前不支援 就可以以任何其他方式完全指定此設定)。建議您設定這個標記 和 deps(//foo) 相比,

--implicit_deps (布林值,default=True)

將此旗標設為 false,會濾除未在 中明確設定的所有結果 並由 Bazel 在其他位置設定。這包含已解決的篩選問題 工具鍊。

--tool_deps (布林值,default=True)

將此標記設為 false 會過濾掉已設定的所有目標, 從查詢目標到他們之間穿越目標的轉換路徑 系統產生的設定 非目標設定: 如果查詢的目標屬於目標設定,則設定 --notool_deps 會 只會傳回同時包含目標設定中的目標。如果查詢原因 目標設定在非目標設定中,設定 --notool_deps 只會傳回 也在非目標設定中調整目標這項設定通常不會影響篩選功能 已解決的工具鍊

--include_aspects (布林值,default=True)

加入切面新增的依附元件。

如果停用此標記,cquery somepath(X, Y) 以及 如果 X 僅透過切面依賴 Y,則 cquery deps(X) | grep 'Y' 會省略 Y。

輸出格式

根據預設,cquery 輸出會產生依依附元件排序的標籤和設定組合清單。 您也可以透過其他選項查看結果。

轉場

--transitions=lite
--transitions=full

設定轉換 會在不同的頂層目標底下 而非頂層目標

舉例來說,目標可能會將轉換程序設定為 tools 屬性中的依附元件。這些稱為「屬性」 轉場效果規則也可以自行設定轉換作業、 稱為規則類別轉換這個輸出格式會輸出 例如轉換類型和對建構的影響 只要設定成「自動重新啟動」 和「在主機維護期間」選項即可

這個輸出格式是由 --transitions 旗標觸發,根據預設, 已設為 NONE。可設為 FULLLITE 模式。FULL 模式輸出內容 規則類別轉換和屬性轉換的資訊,包括 轉換前後的選項差異LITE 種交通方式 輸出的資訊相同,但沒有選項差異。

通訊協定訊息輸出

--output=proto

這個選項會使產生的目標以二進位通訊協定列印 緩衝區格式。如需瞭解通訊協定緩衝區的定義,請前往 src/main/protobuf/analysis_v2.proto.

CqueryResult 是包含 cquery 結果的頂層訊息。這項服務 含有 ConfiguredTarget 訊息清單和 Configuration 清單 訊息。每個 ConfiguredTarget 都有一個值相等的 configuration_idid對應Configuration訊息中的欄位。

--[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 標記。 其中包含來源檔案。

這個輸出格式產生的所有路徑都相對於 execroot,可以取得 透過 bazel info execution_root。如果存在 bazel-out 便利符號連結, 主要存放區中檔案的路徑也會根據工作區解析 目錄。

使用 Starlark 定義輸出格式

--output=starlark

這個輸出格式會呼叫 Starlark 函式,然後將值輸出 。--starlark:file 旗標會指定 Starlark 檔案,以單一參數定義名為 format 的函式。 target。系統會為每個目標呼叫這個函式 結果。或者,為了方便起見,您可以 的函式主體,方法是使用def format(target): return expr --starlark:expr 標記。

「cquery」Starlark 方言

cquery Starlark 環境與 BUILD 或 .bzl 檔案不同。包括 所有核心 Starlark 內建常數和函式 加上下方說明的幾個查詢相關變數,但不包括 (例如) globnativerule,而且不支援載入陳述式。

build_options(target)

build_options(target) 會傳回其鍵為建構選項 ID 的地圖 (請參閱 設定) 以及其值是 Starlark 值值並非法定的 Starlark 版本選項 系統會忽略此地圖中的值。

如果目標為輸入檔案,build_options(target) 會傳回 None,做為輸入檔案 目標則為空值

供應商(目標)

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']"

顯示只有一個輸出內容的目標標籤。本範例使用 檔案中定義的 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 和查詢

cqueryquery彼此相輔相成,成效卓越 不同的領域請先考量下列幾點,再決定自己適合何者:

  • cquery 會追蹤特定 select() 分支版本,如下所示: 模擬您所建構的圖形query不知道哪一個 因此,由於納入所有分支版本,因此系統將過度建議您的分支版本。
  • 為「cquery」精準度,需要建構的圖形數量會比 「query」確實提供。具體情形如下:cquery 會評估已設定的目標,而僅評估query 會評估目標。這麼做需要較多時間,且會耗用較多記憶體。
  • cquery 對 的查詢語言會導致模稜兩可 由 query 避免。例如: 表示 "//foo" 存在於兩種設定中,而 「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 不會自動從建構圖表中抹除建構圖表 因此容易擷取過去的結果 舉個簡單的例子,您可以定義情境 並指示 AI 如何回應服務中心查詢舉例來說,genquery 會在 其 tools 屬性,也就是在 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=&lt;whatever&gt; 加入建構指令。

疑難排解

遞迴目標模式 (/...)

如果遇到以下狀況:

$ 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.

這可能誤表示套件 //foo 不在範圍內 --universe_scope=//foo:app 包含的項目。這是因為 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 "+" -))"