1

Imagine I have a java_binary target triggered by a custom rule that generates source code and places the generated sources under a directory, let's call it "root".

So after the code generation we will have something like this:

// bazel-bin/...../src/com/example/root

root:
  -> Foo.java
  -> Bar.java
  -> utils
        -> Baz.java

Now, I have another target, a java_library, that depends on the previously generated sources, so it depends on the custom rule.

My custom rule definition currently looks something like this:

def _code_generator(ctx):
   outputDir = ctx.actions.declare_directory("root")

   files = [
       ctx.actions.declare_file("root/Foo.java"),
       ctx.actions.declare_file("root/Bar.java"),
       ctx.actions.declare_file("root/utils/Baz.java"),
       // and many, 
       // many other files
   ]

   outputs = []
   outputs.append(outputDir)
   outputs.extend(files)

   ctx.actions.run(
       executable = // executable pointing to the java_binary
       outputs = outputs
       // ....
   )

This works. But as you can see, every anticipated file that is to be generated, is hard-coded in the rule definition. This makes it very fragile, should the code generation produce a different set of files in the future (which it will).

(Without specifying each of the files, as shown above, Bazel will fail the build saying that the files have no generating action)

So I was wondering, is there a way to read the content of the root directory and automatically, somehow, declare each of the files as an output?

What I tried:
The documentation of declare_directory says:

The contents of the directory are not directly accessible from Starlark, but can be expanded in an action command with Args.add_all().

And add_all says:

[...] Each directory File item is replaced by all Files recursively contained in that directory.

This sounds like there could be a way to get access to the individual files in the directory, but I am not sure how.

I tried:

outputDir = ctx.actions.declare_directory("root")
//... 

args = ctx.actions.args()
args.add_all(outputDir)

with the intention to access the individual files later from args, but the build fails with: "Error in add_all: expected value of type sequence or depset for values, got File".

Any other ideas on how to implement the rule, so that I don't have to hard-code each and every file that will be generated?

VCODE
  • 535
  • 5
  • 19
  • 1
    The docs for `arg_name_or_values` say "If only one positional parameter is passed, it is interpreted as values (see below)", and `values` takes a sequence (or depset), so I think you might just need `args.add_all([outputDir])` – ahumesky Oct 21 '22 at 18:14

0 Answers0