将副本/定义传播到目标的所有依赖项 [英] Propagating copts/defines to all of a target's dependencies

查看:94
本文介绍了将副本/定义传播到目标的所有依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个项目,在一个相当复杂的构建系统中,该项目在单个WORKSPACE中涉及多个BUILD文件.简而言之,我的目标是:对于某些特定目标,与所有依赖关系相比,我希望其所有递归依赖项都具有一组额外的属性( copts / defines )目标是以任何其他方式构建的.我还没有找到一种干净的方法.

I have a project that involves multiple BUILD files in a single WORKSPACE, within a fairly complex build system. My goal in short: for some specific target, I want all of its recursive dependencies to be built with an extra set of attributes (copts/defines) compared to when those dependency targets are built in any other way. I have not yet found a way to do this cleanly.

例如,目标G通常使用 copts = [] 构建.如果目标P取决于目标G,并且我运行 bazel build:P ,则我希望两个目标都使用 copts = ["-DMY_DEFINE"] 以及目标G的所有依赖关系,等等.

For example, target G is normally built with copts = []. If target P depends on target G, and I run bazel build :P, I want both targets to be built with copts = ["-DMY_DEFINE"], along with all dependencies of target G, etc.

cc_binary.defines 参数向相反的方向传播:依赖某个目标A的所有目标都将收到目标A的所有 define s.

The cc_binary.defines argument propagates in the opposite direction: all targets that depend on some target A will receive all of target A's defines.

限制:

  • 宁愿避免使用自定义命令行标志,也不控制人们如何称呼 bazel {build,test}
  • 复制整个依赖关系树是不切实际的

似乎无法从BUILD文件或目标中设置 config_setting 的值,因此基于 select 的解决方案似乎无法工作.

It doesn't appear possible to set the value of a config_setting from within a BUILD file or a target, so it seems a select-based solution couldn't work.

以前的工作:

  • https://groups.google.com/g/bazel-discuss/c/rZps4nqYqt8/m/YS_pZD6oAQAJ - 2017, recommends "parallel trees" or custom macros (of which we already have many, it would be challenging to wrap them in another)
  • Propagate copts to all dependencies in Bazel - I believe these all depend on custom command line flags as well

推荐答案

创建用户定义的构建设置不需要命令行标志.如果设置 flag = False ,则实际上不能在命令行上进行设置.您可以使用用户定义的过渡改为设置它.

Creating a user-defined build setting doesn't require command-line flags. If you set flag = False, then it actually can't be set on the command line. You can use a user-defined transition to set it instead.

我认为类似这样的东西可以满足您的需求(将其保存在 extra_copts.bzl 中):

I think something like this will do what you're looking for (save it in extra_copts.bzl):

def _extra_copts_impl(ctx):
    context = cc_common.create_compilation_context(
        defines = depset(ctx.build_setting_value)
    )
    return [CcInfo(compilation_context = context)]

extra_copts = rule(
    implementation = _extra_copts_impl,
    build_setting = config.string_list(flag = False),
)

def _use_extra_copts_implementation(ctx):
    return [ctx.attr._copts[CcInfo]]

use_extra_copts = rule(
    implementation = _use_extra_copts_implementation,
    attrs = "_copts": attr.label(default = "//:extra_copts")},
)

def _add_copts_impl(settings, attr):
    return {"//:extra_copts": ["MY_DEFINE"]}

_add_copts = transition(
    implementation = _add_copts_impl,
    inputs = [],
    outputs = ["//:extra_copts"],
)

def _with_extra_copts_implementation(ctx):
    infos = [d[CcInfo] for d in ctx.attr.deps]
    return [cc_common.merge_cc_infos(cc_infos = infos)]

with_extra_copts = rule(
    implementation = _with_extra_copts_implementation,
    attrs = {
        "deps": attr.label_list(cfg = _add_copts),
        "_allowlist_function_transition": attr.label(
            default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
        )
    },
)

,然后在 BUILD 文件中:

load("//:extra_copts.bzl", "extra_copts", "use_extra_copts", "with_extra_copts")

extra_copts(name = "extra_copts", build_setting_default = [])

use_extra_copts(name = "use_extra_copts")

cc_library(
    name = "G",
    deps = [":use_extra_copts"],
)

with_extra_copts(
    name = "P_deps",
    deps = [":G"],
)

cc_library(
    name = "P",
    deps = [":P_deps"],
)

extra_copts 是构建设置.它直接返回 CcInfo ,这意味着操作很简单任何其他使用相同方法交换的C ++库.它的默认值实际上是空"值. CcInfo 不会对依赖它的库做任何事情.

extra_copts is the build setting. It returns a CcInfo directly, which means it's straightforward to do any other C++ library swapping with the same approach. Its default is effectively an "empty" CcInfo which won't do anything to libraries that depend on it.

with_extra_copts 包装了一组依赖关系,这些依赖关系配置为使用不同的 CcInfo .这是实际更改值的规则,以创建带有不同标志的G的第二个版本.

with_extra_copts wraps a set of dependencies, configured to use a different CcInfo. This is the rule that actually changes the value, to create the second version of G with different flags.

_add_copts with_extra_copts 用于更改 extra_copts 构建设置值的过渡.它可以检查 attr 来做比添加硬编码列表更复杂的事情.

_add_copts is the transition which with_extra_copts uses to change the value of the extra_copts build setting. It could examine attr to do something more sophisticated than adding a hard-coded list.

use_extra_copts extra_copts 中拉出 CcInfo ,以便 cc_library 可以使用它们.

use_extra_copts pulls the CcInfo out of extra_copts so a cc_library can use them.

为避免重写内置的C ++规则,此操作使用包装器规则将副本移出并进行过渡.您可能想要创建宏,以将包装器规则与相应的cc_library捆绑在一起.或者,您可以使用 rules_cc的my_c_archive 作为开始指向创建自定义规则,以重用内置C ++规则的核心实现,同时将构建设置的转换和使用集成到单个规则中.

To avoid rewriting the builtin C++ rules, this uses wrapper rules to pull the copts out and do the transition. You might want to create macros to bundle the wrapper rules along with the corresponding cc_library. Alternatively, you could use rules_cc's my_c_archive as a starting point to create custom rules that reuse the core implementation of the builtin C++ rules while integrating the transition and use of the build setting into a single rule.

这篇关于将副本/定义传播到目标的所有依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆