0

Edit: The example below did actually work, I misinterpreted the output the compiler gave me. The answer may still be helpful to some.

Is there a way for an action in a rule to generate a file that is consumed by a later action in that same rule?

E.g.:

def _example_rule_impl(ctx):
  thefile = ctx.actions.declare_file("required_file.json")

  ctx.actions.write(
    output = thefile,
    content = "CONTENT",
  )

  args = ctx.actions.args()
  args.add("--config", thefile)

  ctx.actions.run(
    inputs = ctx.files.srcs + ctx.files.deps + [thefile],
    outputs = outs,
    arguments = [args],
    progress_message = "Compiling...",
    executable = ctx.executable._compiler,
  )

The main problem with this seems to be, that all action outputs seem to be written to bazel-out, but the run action requires the generated file to be written next to the srcs and deps files in the execroot for it to work. Is there a way to have an action write to the execroot or is this not the correct approach?

1 Answers1

0

Actions taking the outputs of other actions as inputs is a very typical thing to do, and should basically just work as you've set it up. Bazel takes care of handling input and output files, e.g., on linux using a lot of symlinks, mounting things in sandboxes, uploading and downloading files for remote execution, etc.

See https://docs.bazel.build/versions/main/output_directories.html

Also, regarding this line:

inputs = ctx.files.srcs + ctx.files.deps + [thefile],

Depending on what you need to do, you may want to use depsets for performance reasons. See https://docs.bazel.build/versions/main/skylark/depsets.html and in particular at the end https://docs.bazel.build/versions/main/skylark/depsets.html#performance

ahumesky
  • 4,203
  • 8
  • 12
  • Thank you! Turned out it did work all along and I simply misinterpreted the error the compiler gave me. Regarding the depsets: I was using one, but got rid of it while trying to find the problem. However, I'm not sure if I was using it correctly. Would I just put all the files into one despet? inputs = depset(ctx.files.srcs + ctx.files.deps + [thefile])? Or do I create a depset for each of them and add them to the transitive dependencies of each other? – David Heuschmann Dec 01 '21 at 08:47
  • It depends on how your rules are structured. Depsets are mostly for avoiding quadratic memory usage / concatenation in data structures between targets. E.g. foo(name="a", deps=["b"]) foo(name="b", deps=["c"]) foo(name="c", deps=["d"]) without depsets could result in [a, b, c, d], [b, c, d], [c, d], [d] if foo uses lists. However if you're not aggregating elements like that across the "layers" of the build graph for `inputs` then you don't necessarily need depsets. – ahumesky Dec 01 '21 at 16:20