0

I'm working on a problem in which I only want to create a particular rule if a certain Bazel config has been specified (via '--config'). We have been using Bazel since 0.11 and have a bunch of build infrastructure that works around former limitations in Bazel. I am incrementally porting us up to newer versions. One of the features that was missing was compiler transitions, and so we rolled our own using configs and some external scripts.

My first attempt at solving my problem looks like this:

load("@rules_cc//cc:defs.bzl", "cc_library")

# use this with a select to pick targets to include/exclude based on config
# see __build_if_role for an example
def noop_impl(ctx):
    pass

noop = rule(
    implementation = noop_impl,
    attrs = {
        "deps": attr.label_list(),
    },
)

def __sanitize(config):
    if len(config) > 2 and config[:2] == "//":
        config = config[2:]
    return config.replace(":", "_").replace("/", "_")

def build_if_config(**kwargs):
    config = kwargs['config']
    kwargs.pop('config')
    name = kwargs['name'] + '_' + __sanitize(config)

    binary_target_name = kwargs['name']
    kwargs['name'] = binary_target_name
    cc_library(**kwargs)

    noop(
        name = name,
        deps = select({
            config: [ binary_target_name ],
            "//conditions:default": [],
        })
    )

This almost gets me there, but the problem is that if I want to build a library as an output, then it becomes an intermediate dependency, and therefore gets deleted or never built.

For example, if I do this:

build_if_config(
  name="some_lib",
  srcs=[ "foo.c" ],
  config="//:my_config",
)

and then I run

bazel build --config my_config //:some_lib

Then libsome_lib.a does not make it to bazel-out, although if I define it using cc_library, then it does.

Is there a way that I can just create the appropriate rule directly in the macro instead of creating a noop rule and using a select? Or another mechanism?

Thanks in advance for your help!

user961826
  • 564
  • 6
  • 14
  • Ok, it looks like I was misunderstanding what happens when we use the `deps` attribute. I need to create dependencies using the magic `DefaultInfo` https://docs.bazel.build/versions/master/skylark/rules-tutorial.html#creating-a-file – user961826 Aug 31 '20 at 22:51

1 Answers1

0

As I noted in my comment, I was misunderstanding how Bazel figures out its dependencies. The create a file section of The Rules Tutorial explains some of the details, and I followed along here for some of my solution.

Basically, the problem was not that the built files were not sticking around, it was that they were never getting built. Bazel did not know to look in the deps variable and build those things: it seems I had to create an action which uses the deps, and then register an action by returning a (list of) DefaultInfo

Below is my new noop_impl function

def noop_impl(ctx):
    if len(ctx.attr.deps) == 0:
        return None

    # ctx.attr has the attributes of this rule
    dep = ctx.attr.deps[0]
    # DefaultInfo is apparently some sort of globally available
    # class that can be used to index Target objects
    infile = dep[DefaultInfo].files.to_list()[0]
    outfile = ctx.actions.declare_file('lib' + ctx.label.name + '.a')

    ctx.actions.run_shell(
        inputs = [infile],
        outputs = [outfile],
        command = "cp %s %s" % (infile.path, outfile.path),
    )

    # we can also instantiate a DefaultInfo to indicate what output 
    # we provide
    return [DefaultInfo(files = depset([outfile]))]
user961826
  • 564
  • 6
  • 14
  • [DefaultInfo](https://docs.bazel.build/versions/master/skylark/lib/DefaultInfo.html) is a [provider](https://docs.bazel.build/versions/master/skylark/rules.html#providers), for reference if you want to look up more detailed documentation. [alias](https://docs.bazel.build/versions/master/be/general.html#alias) is a builtin rule that does something similar, which might also meet your use case. – Brian Silverman Sep 01 '20 at 23:47
  • Thanks @BrianSilverman I don't think `alias` does what I need, because I would need to create the alias differently depending on the config, like a select that happens before analysis. That seems to not be possible AFAICT – user961826 Sep 14 '20 at 20:45