【问题标题】:Separate compile and linking actions with Bazel使用 Bazel 分离编译和链接操作
【发布时间】:2020-12-18 15:06:39
【问题描述】:

我想知道是否有办法在单独的步骤中使用 Bazel 执行编译和链接操作。如果我执行命令

bazel build -s //main:hello-world

所有的 bazel 子命令都被打印出来了。我知道可以从命令行执行这些子命令,但我想知道如何使用 Bazel 仅执行编译操作,并且仅在单独的步骤中执行链接操作。 提前感谢您的帮助!

【问题讨论】:

  • 在我的情况下,我想反汇编(一些)目标文件进行分析。通过 objcopy 通行证运行它们。逐个查询。太糟糕了,它似乎都被隐藏了。
  • 你可以使用 genrule() 来反汇编,将编译规则 (just_compile) 的输出目标文件作为输入,如下所述?
  • 我目前的想法是制定一个规则,从库中提取目标文件 (ar x),然后将这些目标文件作为输入规则。

标签: c++ compilation linker bazel


【解决方案1】:

不确定您到底在追求什么,但基本上,您可以编写一个自定义规则,将 cc_* 目标作为源传递到其中,并尝试将其操作分开,仅获取您感兴趣的输出,例如:

def _impl(ctx):
    outs = []
    for src in ctx.attr.srcs:
        if hasattr(src, "actions"):
            for action in src.actions:
                if action.mnemonic == "CppCompile":
                    outs.append(action.outputs)
    return DefaultInfo(files = depset(transitive = outs))

just_compile = rule(
    _impl,
    attrs = {
        "srcs": attr.label_list(mandatory = True),
    },

)      

如果我有以下BUILD 文件:

load("//:just_compile.bzl", "just_compile")

just_compile(
    name = "compile_hello",
    srcs = [":hello"],
)

cc_binary(
    name = "hello",
    srcs = ["hello.cpp"],
)

然后你跑(可以加-s观看):

bazel build compile_hello

您将只执行编译步骤(因为我们实际上并没有请求hello 目标,并且树中没有其他需要链接的内容)及其产生的结果:

bazel-bin/
bazel-bin/_objs
bazel-bin/_objs/hello
bazel-bin/_objs/hello/hello.pic.d
bazel-bin/_objs/hello/hello.pic.o

链接助记符是CppLink

所以,是的,您可以将自己附加到特定的操作中。为了辩论起见,这至少是我知道的一种选择。但同样,我不完全确定你到底在追求什么,你想解决什么问题。

【讨论】:

    【解决方案2】:

    您可以使用custom rule 轻松完成编译。您需要使用cc_common API 来执行cc_library 所做的正常操作,但返回DefaultInfo.files provider 中的所有文件。

    对于链接,我只使用cc_binary。如果需要,您还可以使用自定义规则执行类似的操作来拆分各个部分。

    类似这样的:

    load("@rules_cc//cc:action_names.bzl", "C_COMPILE_ACTION_NAME")
    load("@rules_cc//cc:toolchain_utils.bzl", "find_cpp_toolchain")
    
    def _my_c_compile_impl(ctx):
        cc_toolchain = find_cpp_toolchain(ctx)
        source_file = ctx.file.src
        output_file = ctx.actions.declare_file(ctx.label.name + ".o")
        feature_configuration = cc_common.configure_features(
            ctx = ctx,
            cc_toolchain = cc_toolchain,
            requested_features = ctx.features,
            unsupported_features = DISABLED_FEATURES + ctx.disabled_features,
        )
        _, outputs = cc_common.compile(
            actions = ctx.actions,
            cc_toolchain = cc_toolchain,
            srcs = [source_file],
            name = ctx.label.name,
        )
        return [
            DefaultInfo(files = depset(direct = outputs.objects)),
        ]
    
    my_c_compile = rule(
        implementation = _my_c_compile_impl,
        attrs = {
            "src": attr.label(mandatory = True, allow_single_file = True),
            "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
        },
        toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
        incompatible_use_toolchain_transition = True,
        fragments = ["cpp"],
    )
    

    rules_cc my_c_archive example 是一个很好的起点,如果您想自定义超出cc_common.compile 允许的范围。

    如果你想让它成为一个通用的调试工具,你可以将类似的逻辑打包成aspect,以将其应用于任意规则。

    为了快速调试,--save_temps 是另一种技术。

    【讨论】:

      【解决方案3】:

      我认为使用默认 rules_cc 的 Bazel 无法在两个单独的步骤中进行编译和链接。

      你能得到的最接近的是。

      有一个--nobuild 选项会导致在执行构建操作(例如编译、链接等)之前停止构建

      您可以使用aquery 查询构建图中的操作。

      这将为您提供与-s 类似的信息,但不会实际调用命令。

      另一种方法是制定自己的规则,例如

      cc_binary_compilation(
          name = "...",
          srcs = [...]
      )
      
      cc_binary_linking(...)
      

      【讨论】:

      • 您好,谢谢您的回答。你知道,是否也可以通过 Bazel 分两个单独的步骤执行编译和链接?目前,我能做到的唯一方法是从命令行重新执行 SUBCOMMANDS,但这不需要使用 Bazel。
      • 或者,在使用 --nobuild 选项执行 Bazel 构建之后,也可以从命令行一个一个地执行子命令。目前我只能在成功且完整的构建后重新执行命令,但不能在 --nobuild 执行后一一执行。即使我的工作区中存在此目录,我也会收到错误“env: bazel/toolchains/mingw: No such file or directory”。
      • 我认为使用默认 rules_cc 的 Bazel 无法在两个单独的步骤中进行编译和链接。
      • 我明白了,最终我不得不使用自己的规则的实现,这很有效。坦克很多为您的帮助:)
      【解决方案4】:

      您可以指定只接收某个输出组。 所以看看有哪些输出组使用:

      bazel cquery //my_target --output=starlark --starlark:expr="[str(og) for og in target.output_groups]"

      然后仅构建该输出组,此输出组仅用于 c++ 编译(无链接):

      bazel build //my_target --output_groups=compilation_outputs

      诀窍是不要在output_groups 中使用+-,这会修改默认输出组。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-01-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-12
        • 2012-11-19
        • 2019-01-30
        • 1970-01-01
        相关资源
        最近更新 更多