Search code examples
bazel

Bazel select fails inside ctx.file


I am trying to specify build conditions based on the os I'm running bazel from, so in my .bzl script I have a rule that makes all the simlinks from external sources and writes a BUILD file (with ctx.file), in which I'm declaring all the imports and libraries and in those I would like to add the select function. However, when I build I get this error message:

ERROR: no such package '@maya_repo//': Traceback (most recent call last):
        File "/var/tmp/doNotRemove/mdilena_plugins/MayaMathNodes/src/maya.bzl", line 149
                ctx.file("BUILD", _BUILD_STRUC.format(maya_...))
        File "/var/tmp/doNotRemove/mdilena_plugins/MayaMathNodes/src/maya.bzl", line 149, in ctx.file
                _BUILD_STRUC.format(maya_dir = maya_dir)
Invalid character '[' inside replacement field

so here's an example of my code and what I'm trying to achieve:

_BUILD_STRUC = \
"""
# Windows imports
cc_import(
    name = "Foundation-win",
    interface_library = "{maya_dir}/lib/Foundation.lib",
    shared_library = "{maya_dir}/bin/Foundation.dll",
)

cc_import(
    name = "OpenMaya-win",
    interface_library = "{maya_dir}/lib/OpenMaya.lib",
    shared_library = "{maya_dir}/bin/OpenMaya.dll",
)

# Linux imports
cc_import(
    name = "Foundation-lnx",
    shared_library = "{maya_dir}/bin/Foundation.so",
)

cc_import(
    name = "OpenMaya-lnx",
    shared_library = "{maya_dir}/bin/OpenMaya.so",
)

cc_library(
    name = "Foundation",
    deps = select({
        "@bazel_tools//src/conditions:windows": [":Foundation-win"],
        "//conditions:default": [":Foundation-lnx"],
        }),
    includes = ["{maya_dir}/include"],
    visibility = ["//visibility:public"],
)

cc_library(
    name = "OpenMaya",
    deps = select({
        "@bazel_tools//src/conditions:windows": [":OpenMaya-win"],
        "//conditions:default": [":OpenMaya-lnx"],
        }),
    includes = ["{maya_dir}/include"],
    visibility = ["//visibility:public"],
)
"""

def _impl(ctx):
    maya_src = ctx.os.environ["MAYA_LOCATION"]
    maya_ver = ctx.os.environ["MAYA_VERSION"]
    maya_dir = "maya{}".format(maya_ver)
    ctx.symlink(maya_src, maya_dir)
    ctx.file("BUILD", _BUILD_STRUC.format(maya_dir=maya_dir))


link_maya = repository_rule(
    implementation = _impl,
    local = True,
    environ = ["MAYA_LOCATION"],
)

does anyone have any idea why this is happening? I looked at select and configurable attributes docs and seems like that's the way to use it; I wonder if it's me doing something wrong or if there's a bug somewhere.

Thanks for any help!

EDIT:

looks like Bazel really doesn't like using select inside a ctx.file, I'll leave the question open in case someone will be able to shed some light on it. In the meantime I solved it by making all the cc_imports and includes public from the linked repo, while leaving all the cc_libraries with select to my plugin's BUILD file; from there I'm able to use the condition and everything builds.


Solution

  • It looks like the error is coming from this line, specifically the call to string.format.

    ctx.file("BUILD", _BUILD_STRUC.format(maya_dir=maya_dir))
    

    string.format searches the template string for curly braces like {} or {key} and replaces them with positional or keyword arguments.

    You're seeing this error because string.format is mistaking the dict argument to select within the template as something to replace because it starts with a curly brace. Escaping the braces within the template string by doubling them should fix the problem:

    _BUILD_STRUC = \
    """
    ...
    cc_library(
        name = "Foundation",
        deps = select({{
            "@bazel_tools//src/conditions:windows": [":Foundation-win"],
            "//conditions:default": [":Foundation-lnx"],
            }}),
        includes = ["{maya_dir}/include"],
        visibility = ["//visibility:public"],
    )
    ...
    

    FYI, you might find repository_ctx.template easier to work with. It has slightly different semantics: it replaces strings literally, without looking for special characters like {, so escaping is not needed.