如何从 Bazel 中的另一个规则中创建规则
How to create a rule from within another rule in Bazel
情况
我有两个 Skylark 扩展规则:blah_library
和 blah_binary
。 blah_library
的所有传递依赖都通过返回 provider(transitive_deps=...)
传播,并由任何最终依赖的 blah_binary
目标适当处理。
我想做什么
我希望每个 blah_library
也创建一个具有上述所有传递依赖项的 filegroup
,以便我可以单独访问它们。例如,我希望能够将它们作为数据依赖项传递给 cc_binary
。换句话说:
# Somehow have this automatically create a target named `foo__trans_deps`?
blah_library(
name = "foo",
srcs = [...],
deps = [...],
)
cc_binary(
...,
data = [":foo__trans_deps"],
)
我应该怎么做?任何帮助将不胜感激!
我试过的
制作宏
我试过像这样制作一个宏:
_real_blah_library = rule(...)
def blah_library(name, *args, **kwargs):
native.filegroup(
name = name + "__trans_deps",
srcs = ???,
)
_real_blah_library(name=name, *args, **kwargs)
但我不确定如何从宏中访问 _real_blah_library
提供的 provider
,所以我不知道如何填充 filegroup
的 srcs
字段...
修改blah_library
规则的实现
现在我有这样的东西:
_blah_provider = provider(fields=['transitive_deps'])
def _blah_library_impl(ctx):
...
trans_deps = []
for dep in ctx.attr.deps:
trans_deps += dep[_blah_provider].trans_deps
return _blah_provider(trans_deps=trans_deps)
blah_library = rule(impl=_blah_library_impl, ...)
我尝试将以下内容添加到 _blah_library_impl
,但没有成功,因为显然 native.filegroup
无法在规则的实现中调用(“filegroup() cannot be called during the analysis phase
”):
def _blah_library_impl(ctx):
...
trans_deps = []
for dep in ctx.attr.deps:
trans_deps += dep[_blah_provider].trans_deps
native.filegroup(
name = ctx.attr.name + "__trans_deps",
srcs = trans_deps,
)
return _blah_provider(trans_deps=trans_deps)
你不能轻易地创建这样的文件组,但你仍然可以实现你想要的。
如果您想在 genrule.srcs
、filegroup.srcs
、cc_binary.data
等中使用规则,则 return DefaultInfo
提供商(以及_blah_provider
) 并将 files
字段设置为文件的传递闭包。
如果规则在 data
属性中而不是在任何其他属性中(例如 srcs
),如果您想要一组不同的文件,您可以优化解决方案:只需同时设置运行文件-DefaultInfo
中的相关成员。 (坦率地说,我不知道它们之间的区别,我只是将所有运行文件字段设置为相同的值。)
我最终制定了自己的类似 filegroup
的特殊规则,正如@Laszlo 的回答下的评论中所讨论的那样。这是原始代码,以防它对任何人来说都是一个有用的起点:
def _whl_deps_filegroup_impl(ctx):
input_wheels = ctx.attr.src[_PyZProvider].transitive_wheels
output_wheels = []
for wheel in input_wheels:
file_name = wheel.basename
output_wheel = ctx.actions.declare_file(file_name)
# TODO(josh): Use symlinks instead of copying. Couldn't figure out how
# to do this due to issues with constructing absolute paths...
ctx.actions.run(
outputs=[output_wheel],
inputs=[wheel],
arguments=[wheel.path, output_wheel.path],
executable="cp",
mnemonic="CopyWheel")
output_wheels.append(output_wheel)
return [DefaultInfo(files=depset(output_wheels))]
whl_deps_filegroup = rule(
_whl_deps_filegroup_impl,
attrs = {
"src": attr.label(),
},
)
情况
我有两个 Skylark 扩展规则:blah_library
和 blah_binary
。 blah_library
的所有传递依赖都通过返回 provider(transitive_deps=...)
传播,并由任何最终依赖的 blah_binary
目标适当处理。
我想做什么
我希望每个 blah_library
也创建一个具有上述所有传递依赖项的 filegroup
,以便我可以单独访问它们。例如,我希望能够将它们作为数据依赖项传递给 cc_binary
。换句话说:
# Somehow have this automatically create a target named `foo__trans_deps`?
blah_library(
name = "foo",
srcs = [...],
deps = [...],
)
cc_binary(
...,
data = [":foo__trans_deps"],
)
我应该怎么做?任何帮助将不胜感激!
我试过的
制作宏
我试过像这样制作一个宏:
_real_blah_library = rule(...)
def blah_library(name, *args, **kwargs):
native.filegroup(
name = name + "__trans_deps",
srcs = ???,
)
_real_blah_library(name=name, *args, **kwargs)
但我不确定如何从宏中访问 _real_blah_library
提供的 provider
,所以我不知道如何填充 filegroup
的 srcs
字段...
修改blah_library
规则的实现
现在我有这样的东西:
_blah_provider = provider(fields=['transitive_deps'])
def _blah_library_impl(ctx):
...
trans_deps = []
for dep in ctx.attr.deps:
trans_deps += dep[_blah_provider].trans_deps
return _blah_provider(trans_deps=trans_deps)
blah_library = rule(impl=_blah_library_impl, ...)
我尝试将以下内容添加到 _blah_library_impl
,但没有成功,因为显然 native.filegroup
无法在规则的实现中调用(“filegroup() cannot be called during the analysis phase
”):
def _blah_library_impl(ctx):
...
trans_deps = []
for dep in ctx.attr.deps:
trans_deps += dep[_blah_provider].trans_deps
native.filegroup(
name = ctx.attr.name + "__trans_deps",
srcs = trans_deps,
)
return _blah_provider(trans_deps=trans_deps)
你不能轻易地创建这样的文件组,但你仍然可以实现你想要的。
如果您想在 genrule.srcs
、filegroup.srcs
、cc_binary.data
等中使用规则,则 return DefaultInfo
提供商(以及_blah_provider
) 并将 files
字段设置为文件的传递闭包。
如果规则在 data
属性中而不是在任何其他属性中(例如 srcs
),如果您想要一组不同的文件,您可以优化解决方案:只需同时设置运行文件-DefaultInfo
中的相关成员。 (坦率地说,我不知道它们之间的区别,我只是将所有运行文件字段设置为相同的值。)
我最终制定了自己的类似 filegroup
的特殊规则,正如@Laszlo 的回答下的评论中所讨论的那样。这是原始代码,以防它对任何人来说都是一个有用的起点:
def _whl_deps_filegroup_impl(ctx):
input_wheels = ctx.attr.src[_PyZProvider].transitive_wheels
output_wheels = []
for wheel in input_wheels:
file_name = wheel.basename
output_wheel = ctx.actions.declare_file(file_name)
# TODO(josh): Use symlinks instead of copying. Couldn't figure out how
# to do this due to issues with constructing absolute paths...
ctx.actions.run(
outputs=[output_wheel],
inputs=[wheel],
arguments=[wheel.path, output_wheel.path],
executable="cp",
mnemonic="CopyWheel")
output_wheels.append(output_wheel)
return [DefaultInfo(files=depset(output_wheels))]
whl_deps_filegroup = rule(
_whl_deps_filegroup_impl,
attrs = {
"src": attr.label(),
},
)