You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Bazel宏中的‘select不可迭代’报错?

问题:Bazel宏接收select参数时触发"select is not iterable"错误

我定义了ispc_cc_library Bazel宏,在BUILD.bazel中调用时传入包含select的COMMON_DEFINES参数:

COMMON_DEFINES = select({
    "@platforms//os:osx": [
        "OIDN_BNNS",
        "OIDN_STATIC_LIB",
        "OIDN_FILTER_RT",
        "OIDN_FILTER_RTLIGHTMAP",
    ],
    "//conditions:default": [
        "OIDN_DNNL",
        "OIDN_STATIC_LIB",
        "OIDN_FILTER_RT",
        "OIDN_FILTER_RTLIGHTMAP",
    ],
})

ispc_cc_library(
    name = "input_reorder_ispc",
    srcs = [
        "core/color.isph",
        "core/image.isph",
        "core/input_reorder.ispc",
        "core/math.isph",
        "core/reorder.isph",
        "core/tensor.isph",
        "core/vec.isph",
    ],
    out = "input_reorder_ispc.h",
    defines = COMMON_DEFINES,
    ispc_main_source_file = "core/input_reorder.ispc",
)

执行bazel build //...时触发报错:

ERROR: Traceback (most recent call last):
        File "/private/var/tmp/_bazel_vertexwahn/998288db447b21c21cab4093cf36fa19/external/oidn/BUILD.bazel", line 48, column 16, in <toplevel>
                ispc_cc_library(
        File "/private/var/tmp/_bazel_vertexwahn/998288db447b21c21cab4093cf36fa19/external/rules_ispc/ispc.bzl", line 5, column 11, in ispc_cc_library
                if len(defines) > 0:
Error in len: select is not iterable

该宏实现中会对defines执行len(defines)判断并拼接编译参数,直接传固定列表时构建正常。想知道:

  • 正确解决方式是什么?
  • 是否需要将宏转为规则,或是有简便的临时方案?
  • 报错是否因为宏在加载阶段执行,而select在分析阶段解析导致?

重现步骤:

git clone https://github.com/Vertexwahn/rules_ispc.git
cd rules_ispc/tests/defines
bazel build //defines:main # 可正常构建
# 取消rules_ispc/tests/defines/BUILD.bazel第16行的注释:#defines = COMMON_DEFINES,  # this is currenlty not working
# 再次构建
bazel build //defines:main # 会触发报错
解答

报错原因

没错,问题根源就是Bazel的执行阶段差异:

  • 宏是在加载阶段运行的,此时select还只是一个未解析的特殊对象,不是实际的列表,所以调用len()会直接报错。
  • select要到分析阶段才会根据当前平台解析成具体的列表值,而宏无法等到这个阶段再执行代码。

解决方法

临时简便方案(Workaround)

如果不想大改宏的结构,可以修改宏的实现逻辑:不要直接对defines做len()判断或迭代处理,而是把defines直接传递给底层支持select的原生Bazel规则(比如genrule、cc_library的defines参数,这些原生规则本身就支持接收select)。

比如原来宏里可能是手动拼接-D参数的逻辑:

# 错误写法:在宏里处理select对象
if len(defines) > 0:
    compile_flags = ["-D" + d for d in defines]

改成直接把defines传给原生规则:

# 正确写法:交给原生规则处理select
genrule(
    name = "...",
    srcs = ctx.attr.srcs,
    outs = [ctx.attr.out],
    defines = defines,  # 原生genrule支持select
    cmd = "...",
)

这样原生规则会自动在分析阶段解析select,宏不需要在加载阶段处理这个对象。

长期正确方案:将宏转为Bazel规则

宏的本质是加载阶段的代码生成工具,天生无法处理分析阶段才解析的结构(比如select、配置依赖的属性)。而Bazel规则是在分析阶段执行的,能直接拿到解析后的select值,所以把宏改成规则是彻底解决问题的方法。

大致实现步骤:

  1. 把macro定义改成rule定义,在attrs中声明支持的参数,其中defines设为string_list类型(默认支持select)。
  2. 在implementation函数中处理defines,此时它已经是当前平台对应的具体列表,可以安全调用len()或做其他处理。

示例代码:

# 定义规则
ispc_cc_library = rule(
    implementation = _ispc_cc_library_impl,
    attrs = {
        "srcs": attr.label_list(allow_files = [".ispc", ".isph"]),
        "out": attr.output(mandatory = True),
        "defines": attr.string_list(default = []),  # 自动支持select
        "ispc_main_source_file": attr.label(mandatory = True, allow_single_file = [".ispc"]),
        # 其他必要属性,比如工具链、编译选项等
    },
    # 如果生成的是C++库,需要声明提供CcInfo
    provides = [CcInfo],
)

# 实现函数
def _ispc_cc_library_impl(ctx):
    # 这里的defines已经是解析后的列表,可安全处理
    defines = ctx.attr.defines
    compile_flags = []
    if len(defines) > 0:
        compile_flags = ["-D" + d for d in defines]
    
    # 后续生成编译动作、输出文件等逻辑
    # ...

修改后,调用时传入带select的COMMON_DEFINES就能正常工作了。

内容的提问来源于stack exchange,提问作者Vertexwahn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 12:15:38