gpt4 book ai didi

Bazel:你如何获得生成文件的路径?

转载 作者:行者123 更新时间:2023-12-04 11:18:45 28 4
gpt4 key购买 nike

在 Bazel 中,给定构建目标,脚本(在 Bazel 之外运行)如何获取生成文件的路径?

场景:我使用 Bazel 进行构建,完成后,我想将结果复制到服务器。我只需要知道要复制哪些文件。我可以对文件列表进行硬编码,但我不想这样做。

一个简单的例子:这个 Bazel 脚本:

genrule(
name = "main",
srcs = ["main.in"],
outs = ["main.out"],
cmd = "cp $< $@",
)

如果你创建一个名为 main.in 的文件然后运行 ​​ bazel build :main ,巴泽尔报告:
INFO: Found 1 target...
Target //:main up-to-date:
bazel-genfiles/main.out
INFO: Elapsed time: 6.427s, Critical Path: 0.40s

所以有: bazel-genfiles/main.out .但是我可以使用什么机器可读技术来获得该路径? (我可以解析 bazel build 的输出,但我们不鼓励这样做。)

我发现的最接近的是使用 bazel query --output=xml :main , 转储有关 :main 的信息以 XML 格式。输出包括这一行:
<rule-output name="//:main.out"/>

这与我想要的非常接近。但是 name是 Bazel 的标签格式;我不知道如何将其作为路径。

我可以在 name 上做某种字符串替换字段,把它变成 bazel-genfiles/main.out ;但即使这样也不可靠。如果我的 genrule已包含 output_to_bindir = 1 ,那么输出将是 bazel-bin/main.out反而。

此外,并非所有规则都有 <rule-output> XML 输出中的字段。例如,如果我的 BUILD文件有这个代码来制作一个 C 库:
cc_library(
name = "mylib",
srcs = glob(["*.c"])
)
bazel query --output=xml :mylib的输出不包含 <rule-output>或其他任何有用的东西:
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<query version="2">
<rule class="cc_library" location="/Users/mikemorearty/src/bazel/test1/BUILD:8:1" name="//:mylib">
<string name="name" value="mylib"/>
<list name="srcs">
<label value="//:foo.c"/>
</list>
<rule-input name="//:foo.c"/>
<rule-input name="//tools/defaults:crosstool"/>
<rule-input name="@bazel_tools//tools/cpp:stl"/>
</rule>
</query>

最佳答案

您可以使用 bazel aquery 获取此信息。查询
Action 图。

这是一个稍微丰富的示例,其中包含来自单个的两个输出文件
规则:

$ ls
BUILD main.in WORKSPACE
$ cat WORKSPACE
$ cat BUILD
genrule(
name = "main",
srcs = ["main.in"],
outs = ["main.o1", "main.o2"],
cmd = "cp $< $(location main.o1); cp $< $(location main.o2)",
)
$ cat main.in
hello

使用 bazel aquery //:main --output=textproto用机器可读的输出查询 Action 图(原型(prototype)是 analysis.ActionGraphContainer ):
$ bazel aquery //:main --output=textproto >aquery_result 2>/dev/null
$ cat aquery_result
artifacts {
id: "0"
exec_path: "main.in"
}
artifacts {
id: "1"
exec_path: "external/bazel_tools/tools/genrule/genrule-setup.sh"
}
artifacts {
id: "2"
exec_path: "bazel-out/k8-fastbuild/genfiles/main.o1"
}
artifacts {
id: "3"
exec_path: "bazel-out/k8-fastbuild/genfiles/main.o2"
}
actions {
target_id: "0"
action_key: "dd7fd759bbecce118a399c6ce7b0c4aa"
mnemonic: "Genrule"
configuration_id: "0"
arguments: "/bin/bash"
arguments: "-c"
arguments: "source external/bazel_tools/tools/genrule/genrule-setup.sh; cp main.in bazel-out/k8-fastbuild/genfiles/main.o1; cp main.in bazel-out/k8-fastbuild/genfiles/main.o2"
input_dep_set_ids: "0"
output_ids: "2"
output_ids: "3"
}
targets {
id: "0"
label: "//:main"
rule_class_id: "0"
}
dep_set_of_files {
id: "0"
direct_artifact_ids: "0"
direct_artifact_ids: "1"
}
configuration {
id: "0"
mnemonic: "k8-fastbuild"
platform_name: "k8"
}
rule_classes {
id: "0"
name: "genrule"
}

数据并不完全集中在一处,但请注意:
  • 带有 ID 的工件 23对应我们两个想要的
    输出文件,并将这些工件的输出位置列为
    磁盘上文件相对于工作区根目录的路径;
  • artifacts目标 ID 0 的条目与工件相关联
    ID 23 ;和
  • targets ID 为 "0" 的条目与 //:main 相关联
    标签。

  • 鉴于这个简单的结构,我们可以轻松地将脚本组合在一起
    列出与提供的标签对应的所有输出文件。我找不到
    直接依赖于 Bazel 对 analysis.proto 的定义的方式或其
    来自外部存储库的语言绑定(bind),因此您可以修补
    以下脚本进入 bazelbuild/bazel存储库本身:

    工具/list_outputs/list_outputs.py

    # Copyright 2019 The Bazel Authors. All rights reserved.
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    # http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    r"""Parse an `aquery` result to list outputs created for a target.

    Use this binary in conjunction with `bazel aquery` to determine the
    paths on disk to output files of a target.

    Example usage: first, query the action graph for the target that you
    want to analyze:

    bazel aquery //path/to:target --output=textproto >/tmp/aquery_result

    Then, from the Bazel repository:

    bazel run //tools/list_outputs -- \
    --aquery_result /tmp/aquery_result \
    --label //path/to:target \
    ;

    This will print a list of zero or more output files emitted by the given
    target, like:

    bazel-out/k8-fastbuild/foo.genfile
    bazel-out/k8-fastbuild/bar.genfile

    If the provided label does not appear in the output graph, an error will
    be raised.
    """
    from __future__ import absolute_import
    from __future__ import division
    from __future__ import print_function

    import sys

    from absl import app
    from absl import flags
    from google.protobuf import text_format
    from src.main.protobuf import analysis_pb2


    flags.DEFINE_string(
    "aquery_result",
    None,
    "Path to file containing result of `bazel aquery ... --output=textproto`.",
    )
    flags.DEFINE_string(
    "label",
    None,
    "Label whose outputs to print.",
    )


    def die(message):
    sys.stderr.write("fatal: %s\n" % (message,))
    sys.exit(1)


    def main(unused_argv):
    if flags.FLAGS.aquery_result is None:
    raise app.UsageError("Missing `--aquery_result` argument.")
    if flags.FLAGS.label is None:
    raise app.UsageError("Missing `--label` argument.")

    if flags.FLAGS.aquery_result == "-":
    aquery_result = sys.stdin.read()
    else:
    with open(flags.FLAGS.aquery_result) as infile:
    aquery_result = infile.read()
    label = flags.FLAGS.label

    action_graph_container = analysis_pb2.ActionGraphContainer()
    text_format.Merge(aquery_result, action_graph_container)

    matching_targets = [
    t for t in action_graph_container.targets
    if t.label == label
    ]
    if len(matching_targets) != 1:
    die(
    "expected exactly one target with label %r; found: %s"
    % (label, sorted(t.label for t in matching_targets))
    )
    target = matching_targets[0]

    all_artifact_ids = frozenset(
    artifact_id
    for action in action_graph_container.actions
    if action.target_id == target.id
    for artifact_id in action.output_ids
    )
    for artifact in action_graph_container.artifacts:
    if artifact.id in all_artifact_ids:
    print(artifact.exec_path)


    if __name__ == "__main__":
    app.run(main)

    工具/列表输出/构建

    # Copyright 2019 The Bazel Authors. All rights reserved.
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    # http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.

    package(default_visibility = ["//visibility:public"])

    licenses(["notice"]) # Apache 2.0

    filegroup(
    name = "srcs",
    srcs = glob(["**"]),
    )

    py_binary(
    name = "list_outputs",
    srcs = ["list_outputs.py"],
    srcs_version = "PY2AND3",
    deps = [
    "//third_party/py/abseil",
    "//src/main/protobuf:analysis_py_proto",
    ],
    )

    作为一个 Git 补丁,为了您的方便:
    https://gist.github.com/wchargin/5e6a43a203d6c95454aae2886c5b54e4

    请注意,此代码尚未经过审查或验证
    正确性;我提供它主要作为一个例子。如果有用的话
    你,那么也许这个周末我可以为它写一些测试并公关它
    反对巴泽尔本身。

    关于Bazel:你如何获得生成文件的路径?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47859615/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com