Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to work around "select is not iterable" in a macro?

I have a macro called ispc_cc_library. I call it in a BUILD.bazel file this way:

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",
)

When I call the Bazel build command (bazel build //...), I get this error:

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

The implementation of ispc_cc_library looks like this:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

def ispc_cc_library(name, out, ispc_main_source_file, srcs, defines = [], target_compatible_with = [], **kwargs):
    generted_header_filename = out

    ispc_defines_list = ""
    if len(defines) > 0:
        ispc_defines_list = "-D" + " -D".join(defines)

    native.genrule(
        name = "%s_ispc_gen" % name,
        srcs = srcs,
        outs = [name + ".o", generted_header_filename],
        cmd = select({
            "@platforms//os:linux": "$(location @ispc_linux_x86_64//:ispc) %s --target=avx2 --target-os=linux --arch=x86-64 --addressing=64 --pic $(locations %s) --header-outfile=$(location %s) -o $(location %s.o)" % (ispc_defines_list, ispc_main_source_file, generted_header_filename, name),
            "@rules_ispc//:osx_arm64": "$(location @ispc_osx_arm64//:ispc) %s --target=neon --target-os=macos --arch=aarch64 --addressing=64 --pic $(locations %s) --header-outfile=$(location %s) -o $(location %s.o)" % (ispc_defines_list, ispc_main_source_file, generted_header_filename, name),
            "@rules_ispc//:osx_x86_64": "$(location @ispc_osx_x86_64//:ispc) %s --target=sse2 --target-os=macos --arch=x86-64 --addressing=64 --pic $(locations %s) --header-outfile=$(location %s) -o $(location %s.o)" % (ispc_defines_list, ispc_main_source_file, generted_header_filename, name),
            "@platforms//os:windows": "$(location @ispc_windows_x86_64//:ispc) %s --target=avx2 --target-os=windows --arch=x86-64 --addressing=64 $(locations %s) --header-outfile=$(location %s) -o $(location %s.o)" % (ispc_defines_list, ispc_main_source_file, generted_header_filename, name),
        }),
        tools = select({
            "@platforms//os:linux": ["@ispc_linux_x86_64//:ispc"],
            "@rules_ispc//:osx_arm64": ["@ispc_osx_arm64//:ispc"],
            "@rules_ispc//:osx_x86_64": ["@ispc_osx_x86_64//:ispc"],
            "@platforms//os:windows": ["@ispc_windows_x86_64//:ispc"],
        }),
        target_compatible_with = target_compatible_with,
    )
    native.cc_library(
        name = name,
        srcs = [name + ".o"],
        hdrs = [name + ".h"],
        defines = defines,
        target_compatible_with = target_compatible_with,
        **kwargs

It works when I remove the select from COMMON_DEFINES, e.g. on macOS this way:

'''
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",
    ],
})
'''

COMMON_DEFINES = [
    "OIDN_BNNS",
    "OIDN_STATIC_LIB",
    "OIDN_FILTER_RT",
    "OIDN_FILTER_RTLIGHTMAP",
]

As Bazel reports select is not iterable what is the right way to solve this issue? Do I need to convert ispc_cc_library macro to a rule? Or is there a easy workaround?

Is it breaking because macros are evaluated during loading phase and the select is resolved (afterwards) during the analysis phase?

Steps to reproduce:

git clone https://github.com/Vertexwahn/rules_ispc.git
cd rules_ispc/tests/defines
bazel build //defines:main # should work
# now remove comment from line 16 in rules_ispc/tests/defines/BUILD.bazel -> #defines = COMMON_DEFINES,  # this is currenlty not working
# build again
bazel build //defines:main # should fail

>Solution :

You are correct that the problem is the select isn’t resolved until the loading phase, which is after the macro is done. Another way to look at it: if you build the target for the host and the target, your macro is only evaluated once, but the select may resolve differently.

Your situation looks like you should write a rule. The simple approach is wrap invoking your rule and native.cc_library in a macro together. I think all of your logic should be easy to split like that.

You could also integrate with the C/C++ rules and effectively re-implement cc_library using the built-in helpers. For a simple usage of cc_library like you have, that’s pretty straightforwards. I recommend copying the boilerplate from the rules_cc my_c_compile example.

Another approach to this kind of problem is passing around the dicts that go inside a select. You can manipulate those from macros (prepend to every element of the values, add more elements to the end of every value, wrap a string formatting operation around every element of the values, etc), and then wrap them in native.select at the end. That’s kind of a pain to debug though, I would not recommend it here.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading