英文:
"bazel aquery" returns no action information for java_proto_library
问题
我打算使用 bazel aquery
来探索目标的输入和输出,但发现 java_proto_library
没有产生输出。
以一个简单的示例为例:
proto_library(
name = "example_proto",
srcs = ["example.proto"],
)
java_proto_library(
name = "example_java_proto",
deps = [":example_proto"],
)
运行 bazel aquery //:example_proto
可以得到预期的操作信息,但运行 bazel aquery //:example_java_proto
只返回 INFO 日志:
INFO: 分析目标 //:example_java_proto(已加载0个软件包,配置了15个目标)。
INFO: 找到1个目标...
INFO: 耗时:0.151秒
INFO: 0个进程。
INFO: 构建已成功完成,共计0个操作
完整的示例代码位于 https://github.com/theothertomelliott/bazel-issues/tree/java_proto_aquery
这是否是 java_proto_library
的特殊问题(我曾看到有关此规则的源代码存档和其他奇怪问题),还是一个错误,或者是我在配置中忽略了什么?
英文:
I'm looking to use bazel aquery
to explore inputs and outputs for targets, and have found that java_proto_library
produces no output.
For a simple example:
proto_library(
name = "example_proto",
srcs = ["example.proto"],
)
java_proto_library(
name = "example_java_proto",
deps = [":example_proto"],
)
bazel aquery //:example_proto
returns the action information as expected, but bazel aquery //:example_java_proto
returns only INFO logging:
INFO: Analyzed target //:example_java_proto (0 packages loaded, 15 targets configured).
INFO: Found 1 target...
INFO: Elapsed time: 0.151s
INFO: 0 processes.
INFO: Build completed successfully, 0 total actions
Full example code at https://github.com/theothertomelliott/bazel-issues/tree/java_proto_aquery
Is this a particular quirk of java_proto_library
(I've seen issues raised about src jars and other oddities of this rule), a bug, or something I'm missing in the config?
答案1
得分: 2
这是因为 java_proto_library
的实现细节,以及构建图的构建方式和查询函数的查询方式。
java_proto_library
实际上并没有注册任何操作:JavaProtoLibrary.java。相反,它在所有的依赖上运行一个切面(aspect):BazelJavaProtoLibraryRule.java#L49-L52。然后,在所有 java_proto_library
的 proto 依赖上评估该切面,将 java proto 操作注册到 proto 依赖上:JavaProtoAspect.java#L206。
所以,bazel aquery //:example_java_proto
在于该目标实际上没有任何操作。但是 bazel aquery //:example_proto
也不会返回 java proto 操作。首先需要使用 --include_aspects
,这样 aquery 将输出附加到目标的所有切面的信息。
第二个问题是在运行 aquery
时构建图的状态:
<pre>
$ bazel clean
INFO: Starting clean (this may take a while). Consider using --async if the clean takes more than several minutes.
$ <b>bazel aquery //:example_proto --include_aspects</b> 2>/dev/null | grep action
action 'Generating Descriptor Set proto_library //:example_proto'
$ <b>bazel aquery //:example_java_proto --include_aspects</b> 2>/dev_null | grep action
(nothing)
$ <b>bazel aquery //:example_proto --include_aspects</b> 2>/dev/null | grep action
action 'Generating Descriptor Set proto_library //:example_proto'
action 'Generating Java (Immutable) proto_library //:example_proto'
action 'Building libexample_proto-speed.jar (1 source jar)'
action 'Compiling Java headers libexample_proto-speed-hjar.jar (1 source jar)'
</pre>
所以当首次查询 example_proto
时,返回一个操作,然后查询 example_java_proto
,它不返回任何操作,然后再次查询 example_proto
,它返回 4 个操作:之前的一个操作和一些 java 操作。这是因为当分析 example_java_proto
时,它注册的切面运行,并且图中现在包含来自切面的操作。
这基本上是设计如此,因为 Bazel 不会查看超出其所要求查询或构建的范围。如果某个包中有一个 cc_proto_library
,除非被要求加载或分析该包,否则 Bazel 不会知道它。切面可以来自任何地方,因此为了获取完整信息,Bazel 必须加载存储库中的每个 BUILD 文件,这对于大型存储库来说是不可扩展的。
rdeps
查询函数可以用来获取所有内容:
$ bazel clean
INFO: Starting clean (this may take a while). Consider using --async if the clean takes more than several minutes.
$ bazel cquery "rdeps(//:example_proto, ...)"
INFO: Analyzed 3 targets (20 packages loaded, 908 targets configured).
INFO: Found 3 targets...
//:example_proto (45d0b89373a0dfd75ac4b432cf2b12138c1203b34bdec57557dfef52e7a6ed03)
INFO: Elapsed time: 0.408s
INFO: 0 processes.
INFO: Build completed successfully, 0 total actions
$ bazel aquery //:example_proto --include_aspects 2>/dev_null | grep action
action 'Generating Descriptor Set proto_library //:example_proto'
action 'Generating Java (Immutable) proto_library //:example_proto'
action 'Building libexample_proto-speed.jar (1 source jar)'
action 'Compiling Java headers libexample_proto-speed-hjar.jar (1 source jar)'
rdeps(//:example_proto, //...)
将找到 example_proto
的所有反向依赖项,而 //...
则加载整个存储库。请注意,这里需要使用 cquery
,而不是 query
,因为 query
不会运行分析阶段(在此阶段创建操作),而 cquery
会运行分析阶段。
英文:
This is because of the implementation details of java_proto_library
, and because of how the build graph is built and how the query functions query it.
java_proto_library
doesn't actually register any actions itself: JavaProtoLibrary.java. Instead, it run an aspect over all its deps: BazelJavaProtoLibraryRule.java#L49-L52. That aspect is then evaluated on all the proto dependencies of the java_proto_library
, and registers the java proto actions with the proto dependencies: JavaProtoAspect.java#L206
So bazel aquery //:example_java_proto
is correct in that that target really has no actions. But bazel aquery //:example_proto
also doesn't return java proto actions. The first thing that's needed is --include_aspects
, so that aquery outputs information from any aspects attached to the targets.
The 2nd thing is the state of the build graph when aquery
is run:
<pre>
$ bazel clean
INFO: Starting clean (this may take a while). Consider using --async if the clean takes more than several minutes.
$ <b>bazel aquery //:example_proto --include_aspects</b> 2>/dev/null | grep action
action 'Generating Descriptor Set proto_library //:example_proto'
$ <b>bazel aquery //:example_java_proto --include_aspects</b> 2>/dev/null | grep action
(nothing)
$ <b>bazel aquery //:example_proto --include_aspects</b> 2>/dev/null | grep action
action 'Generating Descriptor Set proto_library //:example_proto'
action 'Generating Java (Immutable) proto_library //:example_proto'
action 'Building libexample_proto-speed.jar (1 source jar)'
action 'Compiling Java headers libexample_proto-speed-hjar.jar (1 source jar)'
</pre>
So when example_proto
is first queried, it returns 1 action, then example_java_proto
is queried, and it returns nothing, then example_proto
is queried again, and it returns 4 actions: the one from before, and some java ones. This is because when example_java_proto
is analyzed, the aspect it registers runs and the graph now contains the actions from the aspect.
This is basically by design, because Bazel doesn't look at anything beyond what it's asked to query or build. If there were a cc_proto_library
in some package somewhere, Bazel won't know about it until it's asked to load or analyze that package. Aspects can come from anywhere, so in order to get complete information, Bazel would have to load every BUILD file in the repository, which won't scale for large repositories.
The rdeps
query function can be used to get everything:
$ bazel clean
INFO: Starting clean (this may take a while). Consider using --async if the clean takes more than several minutes.
$ bazel cquery "rdeps(//:example_proto, ...)"
INFO: Analyzed 3 targets (20 packages loaded, 908 targets configured).
INFO: Found 3 targets...
//:example_proto (45d0b89373a0dfd75ac4b432cf2b12138c1203b34bdec57557dfef52e7a6ed03)
INFO: Elapsed time: 0.408s
INFO: 0 processes.
INFO: Build completed successfully, 0 total actions
$ bazel aquery //:example_proto --include_aspects 2>/dev/null | grep action
action 'Generating Descriptor Set proto_library //:example_proto'
action 'Generating Java (Immutable) proto_library //:example_proto'
action 'Building libexample_proto-speed.jar (1 source jar)'
action 'Compiling Java headers libexample_proto-speed-hjar.jar (1 source jar)'
rdeps(//:example_proto, //...)
will find all the reverse dependencies of example_proto
, and the //...
loads the entire repository. Note that cquery
is needed here, rather than query
, because query
doesn't run the analysis phase, where actions are created, whereas cquery
does run the analysis phase.
答案2
得分: 1
java rules 是一个内置的 Bazel 规则,其实现是基于切面(aspects)的,因此如果你首先运行以下命令:
bazel build --nobuild //:example_java_proto
然后运行:
bazel aquery '//:example_proto' --include_aspects=true
你应该会看到一个带有 Java 特定操作的动作图。
英文:
java rules is a built-in bazel rule, and its implementation is based on aspects,
so if you first run
bazel build --nobuild //:example_java_proto
and then
bazel aquery '//:example_proto' --include_aspects=true
you should see an action graph, enriched with java specific actions
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论