将副本/定义传播到目标的所有依赖项 [英] Propagating copts/defines to all of a target's dependencies
问题描述
我有一个项目,在一个相当复杂的构建系统中,该项目在单个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 define
s.
限制:
- 宁愿避免使用自定义命令行标志,也不控制人们如何称呼
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年,建议使用并行树"或自定义宏(我们已经有很多宏了,将它们包装到另一个宏中将很困难)
- 将副本传播给Bazel中的所有依赖项-我相信这些都取决于自定义命令行标志
- 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屋!