首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >生成许多规则的bazel规则“模板”

生成许多规则的bazel规则“模板”
EN

Stack Overflow用户
提问于 2022-06-04 03:07:10
回答 1查看 32关注 0票数 0

我有一些输入文件叫做src0,src1,src2,.srcN,它们需要编译成dst1,dst2,dst3,.dstN。

我有一个简单的my_convert规则,以及生成完整文件名路径的宏:

代码语言:javascript
复制
def src_filename(id):
  return ":some/path/to/src{}".format(id)

def dest_filename(id):
  return ":some/path/to/dest{}".format(id)
代码语言:javascript
复制
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循环中的规则吗?(我将回到编写一个脚本来生成包含所有规则的构建文件,但我希望我不必这样做)

EN

回答 1

Stack Overflow用户

发布于 2022-06-07 15:05:23

它需要来自某些配置吗?或者是类似于“目录中的所有文件”?因为这样你就可以做这样的事情:

代码语言:javascript
复制
my_convert(
  name = "converstions",
  srcs = glob(["some/path/to/src*"]),
)
代码语言:javascript
复制
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

如果不能基于目录,另一种方法是为每个文件生成目标,然后显式地构建所需的子集。就像这样:

代码语言:javascript
复制
generate_my_conversions(glob(["some/path/to/src*"]))
代码语言:javascript
复制
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

这避免了每个文件实例化规则(在有更多文件之前,区别/优势可能重要,也可能不重要)。

如果它确实需要成为一个标志,这是可能的,虽然有点尴尬,因为有一个标志来配置一个特定的单独目标(标志通常是适用于整个构建的东西)是有点不寻常的。就像这样:

代码语言:javascript
复制
$ tree
.
├── package
│   ├── BUILD
│   ├── defs.bzl
│   └── some
│       └── path
│           └── to
│               ├── src0
│               ├── src1
│               ├── src10
│               ├── src11
│               ├── src12
│               ├── src2
│               ├── src3
│               ├── src4
│               ├── src5
│               ├── src6
│               ├── src7
│               ├── src8
│               └── src9
└── WORKSPACE

package/defs.bzl

代码语言:javascript
复制
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

代码语言:javascript
复制
load(":defs.bzl", "my_convert")

my_convert(
  name = "conversions",
  srcs = glob(["some/path/to/src*"]),
)

请注意,glob接收可能需要的每个文件,因为Starlark无法在加载时连接标志的值以生成文件列表(即在计算构建文件时)。

代码语言:javascript
复制
$ 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
代码语言:javascript
复制
$ 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 actions
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72496773

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档