本页介绍了如何开始使用 Bazel 的查询语言来跟踪代码中的依赖项。
如需了解语言详情和 --output
标志详情,请参阅参考手册:Bazel 查询参考和 Bazel cquery 参考。您可以在命令行中输入 bazel help query
或 bazel help cquery
来获取帮助。
如需在执行查询时忽略缺少目标等错误,请使用 --keep_going
标志。
查找规则的依赖项
如需查看 //foo
的依赖项,请在 bazel 查询中使用 deps
函数:
$ bazel query "deps(//foo)" //foo:foo //foo:foo-dep ...
这是构建 //foo
所需的所有目标的集合。
跟踪两个软件包之间的依赖关系链
库 //third_party/zlib:zlibonly
不在 //foo
的 BUILD 文件中,但它是一个间接依赖项。如何跟踪此依赖项路径? 这里有两个实用函数:allpaths
和 somepath
。如果您只关心所构建制品中包含的内容,而不关心每个可能的作业,您可能还需要使用 --notool_deps
排除工具依赖项。
如需直观呈现所有依赖项的图表,请通过 dot
命令行工具传递 bazel 查询输出:
$ bazel query "allpaths(//foo, third_party/...)" --notool_deps --output graph | dot -Tsvg > /tmp/deps.svg
当依赖关系图很大且很复杂时,从单个路径开始可能会很有帮助:
$ bazel query "somepath(//foo:foo, third_party/zlib:zlibonly)" //foo:foo //translations/tools:translator //translations/base:base //third_party/py/MySQL:MySQL //third_party/py/MySQL:_MySQL.so //third_party/mysql:mysql //third_party/zlib:zlibonly
如果您未指定 --output graph
和 allpaths
,则会获得扁平化的依赖关系图列表。
$ bazel query "allpaths(//foo, third_party/...)" ...many errors detected in BUILD files... //foo:foo //translations/tools:translator //translations/tools:aggregator //translations/base:base //tools/pkg:pex //tools/pkg:pex_phase_one //tools/pkg:pex_lib //third_party/python:python_lib //translations/tools:messages //third_party/py/xml:xml //third_party/py/xml:utils/boolean.so //third_party/py/xml:parsers/sgmlop.so //third_party/py/xml:parsers/pyexpat.so //third_party/py/MySQL:MySQL //third_party/py/MySQL:_MySQL.so //third_party/mysql:mysql //third_party/openssl:openssl //third_party/zlib:zlibonly //third_party/zlib:zlibonly_v1_2_3 //third_party/python:headers //third_party/openssl:crypto
旁注:隐式依赖项
//foo
的 BUILD 文件从不引用 //translations/tools:aggregator
。那么,直接依赖项在哪里?
某些规则包含对其他库或工具的隐式依赖关系。例如,若要构建 genproto
规则,您需要先构建协议编译器,因此每个 genproto
规则都隐式依赖于协议编译器。这些依赖项未在 build 文件中提及,但由 build 工具添加。目前,整套隐式依赖项尚未记录在文档中。使用 --noimplicit_deps
可从查询结果中过滤掉这些依赖项。对于 cquery,这将包括已解析的工具链。
反向依赖项
您可能想知道依赖于某个目标的一组目标。例如,如果您要更改某些代码,可能需要了解您即将破坏哪些其他代码。您可以使用 rdeps(u, x)
在 u
的传递闭包中查找 x
中目标的反向依赖项。
Bazel 的 Sky Query 支持 allrdeps
函数,该函数可让您在指定的 Universe 中查询反向依赖项。
其他用途
您可以使用 bazel query
分析许多依赖关系。
What exists ...
foo
下有哪些软件包?
bazel query 'foo/...' --output package
foo
软件包中定义了哪些规则?
bazel query 'kind(rule, foo:*)' --output label_kind
foo
软件包中的规则会生成哪些文件?
bazel query 'kind("generated file", //foo:*)'
Starlark 宏 foo
生成哪些目标?
bazel query 'attr(generator_function, foo, //path/to/search/...)'
构建 //foo
需要哪些 BUILD 文件?
bazel query 'buildfiles(deps(//foo))' | cut -f1 -d:
test_suite
会扩展为哪些单独的测试?
bazel query 'tests(//foo:smoke_tests)'
其中哪些是 C++ 测试?
bazel query 'kind(cc_.*, tests(//foo:smoke_tests))'
其中哪些是小型企业?中等?大号?
bazel query 'attr(size, small, tests(//foo:smoke_tests))' bazel query 'attr(size, medium, tests(//foo:smoke_tests))' bazel query 'attr(size, large, tests(//foo:smoke_tests))'
foo
下与某种模式匹配的测试有哪些?
bazel query 'filter("pa?t", kind(".*_test rule", //foo/...))'
该模式是一个正则表达式,应用于规则的完整名称。这类似于执行
bazel query 'kind(".*_test rule", //foo/...)' | grep -E 'pa?t'
哪个软件包包含文件 path/to/file/bar.java
?
bazel query path/to/file/bar.java --output=package
path/to/file/bar.java?
的 build 标签是什么
bazel query path/to/file/bar.java
哪些规则目标将文件 path/to/file/bar.java
作为来源?
fullname=$(bazel query path/to/file/bar.java) bazel query "attr('srcs', $fullname, ${fullname//:*/}:*)"
存在哪些软件包依赖项 ...
foo
依赖于哪些软件包?(我需要签出哪些内容才能构建 foo
)
bazel query 'buildfiles(deps(//foo:foo))' --output package
foo
树依赖于哪些软件包(不包括 foo/contrib
)?
bazel query 'deps(foo/... except foo/contrib/...)' --output package
存在哪些规则依赖项 ...
bar 依赖于哪些 genproto 规则?
bazel query 'kind(genproto, deps(bar/...))'
在 servlet 树中查找 Java 二进制规则以传递方式依赖的某个 JNI (C++) 库的定义。
bazel query 'some(kind(cc_.*library, deps(kind(java_binary, //java/com/example/frontend/...))))' --output location
...现在,找到依赖于这些二进制文件的所有 Java 二进制文件的定义
bazel query 'let jbs = kind(java_binary, //java/com/example/frontend/...) in let cls = kind(cc_.*library, deps($jbs)) in $jbs intersect allpaths($jbs, $cls)'
存在哪些文件依赖项 ...
构建 foo 需要哪些 Java 源文件的完整集?
源文件:
bazel query 'kind("source file", deps(//path/to/target/foo/...))' | grep java$
生成的文件:
bazel query 'kind("generated file", deps(//path/to/target/foo/...))' | grep java$
构建 QUX 的测试所需的完整 Java 源文件集是什么?
源文件:
bazel query 'kind("source file", deps(kind(".*_test rule", javatests/com/example/qux/...)))' | grep java$
生成的文件:
bazel query 'kind("generated file", deps(kind(".*_test rule", javatests/com/example/qux/...)))' | grep java$
X 和 Y 之间在依赖项方面存在哪些差异 ...
//foo
依赖于哪些 //foo:foolib
不依赖的目标?
bazel query 'deps(//foo) except deps(//foo:foolib)'
foo
测试依赖哪些 //foo
生产二进制文件不依赖的 C++ 库?
bazel query 'kind("cc_library", deps(kind(".*test rule", foo/...)) except deps(//foo))'
为什么存在此依赖关系 ...
为什么 bar
依赖于 groups2
?
bazel query 'somepath(bar/...,groups2/...:*)'
获得此查询的结果后,您通常会发现,单个目标会突出显示为 bar
的意外或严重且不受欢迎的依赖项。然后,您可以进一步优化查询,使其变为:
显示从 docker/updater:updater_systest
(一个 py_test
)到它所依赖的某个 cc_library
的路径:
bazel query 'let cc = kind(cc_library, deps(docker/updater:updater_systest)) in somepath(docker/updater:updater_systest, $cc)'
为什么库 //photos/frontend:lib
依赖于同一库 //third_party/jpeglib
和 //third_party/jpeg
的两个变体?
此查询可简化为:“显示同时依赖于这两个库的 //photos/frontend:lib
子图”。按拓扑顺序显示时,结果的最后一个元素是最有可能的罪魁祸首。
bazel query 'allpaths(//photos/frontend:lib, //third_party/jpeglib) intersect allpaths(//photos/frontend:lib, //third_party/jpeg)' //photos/frontend:lib //photos/frontend:lib_impl //photos/frontend:lib_dispatcher //photos/frontend:icons //photos/frontend/modules/gadgets:gadget_icon //photos/thumbnailer:thumbnail_lib //third_party/jpeg/img:renderer
什么取决于 ...
横线下方的哪些规则取决于 Y?
bazel query 'bar/... intersect allpaths(bar/..., Y)'
在 T 的软件包中,哪些目标直接依赖于 T?
bazel query 'same_pkg_direct_rdeps(T)'
如何打破依赖关系 ...
我必须断开哪些依赖项路径才能使 bar
不再依赖于 X?
如需将图表输出到 svg
文件,请执行以下操作:
bazel query 'allpaths(bar/...,X)' --output graph | dot -Tsvg > /tmp/dep.svg
其他
//foo-tests
build 中有多少个连续步骤?
遗憾的是,查询语言目前无法为您提供从 x 到 y 的最长路径,但它可以找到距离起点最远的节点(或者说一个最远的节点),也可以显示从 x 到每个依赖项 y 的最长路径的长度。使用 maxrank
:
bazel query 'deps(//foo-tests)' --output maxrank | tail -1 85 //third_party/zlib:zutil.c
结果表明,此 build 中存在长度为 85 的路径,这些路径必须按顺序出现。