我有一些输入文件叫做src0,src1,src2,.srcN,它们需要编译成dst1,dst2,dst3,.dstN。
我有一个简单的my_convert规则,以及生成完整文件名路径的宏:
def src_filename(id):
return ":some/path/to/src{}".format(id)
def dest_filename(id):
return ":some/path/to/dest{}".format(id)my_convert(
src=src_filename(0),
dest=dest_filename(0)
)
my_convert(
src=src_filename(1),
dest=dest_filename(1)
)
...现在,我可以复制和粘贴my_convert N次,但是N有时是数百次,文件的数量取决于某些配置.因此,我非常希望有一种动态规则,在那里我可以从命令行传入'N‘,然后调用0.N范围内的所有’d,然后调用my_convert。
在巴泽尔内部做这件事的最好方法是什么?有什么方法来描述for循环中的规则吗?(我将回到编写一个脚本来生成包含所有规则的构建文件,但我希望我不必这样做)
发布于 2022-06-07 15:05:23
它需要来自某些配置吗?或者是类似于“目录中的所有文件”?因为这样你就可以做这样的事情:
my_convert(
name = "converstions",
srcs = glob(["some/path/to/src*"]),
)def _my_convert_impl(ctx):
outputs = []
for src in ctx.files.srcs:
output = ctx.actions.declare_file(src.basename + ".out")
outputs.append(output)
ctx.actions.run_shell(
inputs = [src],
outputs = [output],
command = "wc -l '%s' > '%s'" % (src.path, output.path),
mnemonic = "Convert",
progress_message = "Convert %{input}",
)
return [DefaultInfo(files = depset(outputs))]
my_convert = rule(
implementation = _my_convert_impl,
attrs = {
"srcs": attr.label_list(allow_files = True),
},
)然后是bazel build //package:conversions。
如果不能基于目录,另一种方法是为每个文件生成目标,然后显式地构建所需的子集。就像这样:
generate_my_conversions(glob(["some/path/to/src*"]))def generate_my_conversions(files):
for file in files:
my_convert(
name = "convert_" + file.replace("/", "_"), # this might need adjusting
src = file,
)然后构建您想要的目标(可能生成列表):bazel build //package:convert_some_path_to_src0 //package:convert_some_path_to_src1 //package:convert_some_path_to_src2 //package:convert_some_path_to_srcN
使用输出文件也有类似的方法:https://docs.bazel.build/versions/main/skylark/rules.html#declaring-outputs
这避免了每个文件实例化规则(在有更多文件之前,区别/优势可能重要,也可能不重要)。
如果它确实需要成为一个标志,这是可能的,虽然有点尴尬,因为有一个标志来配置一个特定的单独目标(标志通常是适用于整个构建的东西)是有点不寻常的。就像这样:
$ tree
.
├── package
│ ├── BUILD
│ ├── defs.bzl
│ └── some
│ └── path
│ └── to
│ ├── src0
│ ├── src1
│ ├── src10
│ ├── src11
│ ├── src12
│ ├── src2
│ ├── src3
│ ├── src4
│ ├── src5
│ ├── src6
│ ├── src7
│ ├── src8
│ └── src9
└── WORKSPACEpackage/defs.bzl
def _my_convert_impl(ctx):
file_count = ctx.attr.file_count[FileCountToConvertProvider].count
if file_count < 0:
fail("Must set flag --%s" % ctx.attr.file_count.label)
if file_count > len(ctx.files.srcs):
fail("More files requested than sources")
# srcs could be in any order, so extract the source number from the file name
srcs = {}
for src in ctx.files.srcs:
file_number_char_count = 0
# reversed() doesn't work with string in Starlark...
for i in range(len(src.basename) - 1, 0, -1):
if src.basename[i].isdigit():
file_number_char_count += 1
else:
break
file_number = int(src.basename[-file_number_char_count:])
srcs[file_number] = src
outputs = []
for i in range(file_count):
src = srcs[i]
if src.path.startswith(ctx.label.package + "/"):
package_relative_path = src.path[len(ctx.label.package) + 1:]
else:
package_relative_path = src.path
output = ctx.actions.declare_file(package_relative_path.replace("src", "dst"))
outputs.append(output)
ctx.actions.run_shell(
inputs = [src],
outputs = [output],
command = "wc -l '%s' > '%s'" % (src.path, output.path),
mnemonic = "Convert",
progress_message = "Convert %{input}",
)
return [DefaultInfo(files = depset(outputs))]
_my_convert = rule(
implementation = _my_convert_impl,
attrs = {
"srcs": attr.label_list(allow_files = True, mandatory = True),
"file_count": attr.label(),
},
)
FileCountToConvertProvider = provider(fields = ["count"])
def _file_count_to_convert_flag_impl(ctx):
return FileCountToConvertProvider(count = ctx.build_setting_value)
_file_count_to_convert_flag = rule(
implementation = _file_count_to_convert_flag_impl,
build_setting = config.int(flag = True),
)
# Use a macro to create the my_convert target + associated flag
def my_convert(name, srcs):
flag_name = name + "_file_count"
_file_count_to_convert_flag(
name = flag_name,
build_setting_default = -1,
)
_my_convert(
name = name,
srcs = srcs,
file_count = flag_name,
)package/BUILD
load(":defs.bzl", "my_convert")
my_convert(
name = "conversions",
srcs = glob(["some/path/to/src*"]),
)请注意,glob接收可能需要的每个文件,因为Starlark无法在加载时连接标志的值以生成文件列表(即在计算构建文件时)。
$ bazel build //package:conversions --//package:conversions_file_count=5
INFO: Analyzed target //package:conversions (4 packages loaded, 20 targets configured).
INFO: Found 1 target...
Target //package:conversions up-to-date:
bazel-bin/package/some/path/to/dst0
bazel-bin/package/some/path/to/dst1
bazel-bin/package/some/path/to/dst2
bazel-bin/package/some/path/to/dst3
bazel-bin/package/some/path/to/dst4
INFO: Elapsed time: 0.302s, Critical Path: 0.03s
INFO: 6 processes: 1 internal, 5 linux-sandbox.
INFO: Build completed successfully, 6 total actions$ bazel build //package:conversions --//package:conversions_file_count=11
INFO: Build option --//package:conversions_file_count has changed, discarding analysis cache.
INFO: Analyzed target //package:conversions (0 packages loaded, 20 targets configured).
INFO: Found 1 target...
Target //package:conversions up-to-date:
bazel-bin/package/some/path/to/dst0
bazel-bin/package/some/path/to/dst1
bazel-bin/package/some/path/to/dst2
bazel-bin/package/some/path/to/dst3
bazel-bin/package/some/path/to/dst4
bazel-bin/package/some/path/to/dst5
bazel-bin/package/some/path/to/dst6
bazel-bin/package/some/path/to/dst7
bazel-bin/package/some/path/to/dst8
bazel-bin/package/some/path/to/dst9
bazel-bin/package/some/path/to/dst10
INFO: Elapsed time: 0.114s, Critical Path: 0.02s
INFO: 7 processes: 1 internal, 6 linux-sandbox.
INFO: Build completed successfully, 7 total actionshttps://stackoverflow.com/questions/72496773
复制相似问题