0

Suppose I am writing a custom Bazel rule for foo-compiler.

The user provides a list of source-files to the rule:

foo_library(
  name = "hello",
  srcs = [ "A.foo", "B.foo" ],
)

To build this without Bazel, the steps would be:

  1. Create a config file config.json that lists the sources:
{
  "srcs": [ "./A.foo", "./B.foo" ]
}
  1. Place the config alongside the sources:
$ ls .
A.foo
B.foo
config.json
  1. Call foo-compiler in that directory:
$ foo-compiler .

Now, in my Bazel rule implementation I can declare a file like this:

  config_file = ctx.actions.declare_file("config.json")

  ctx.actions.write(
    output = config_file,
    content = json_for_srcs(ctx.files.srcs),
  )

The file is created and it has the right content.

However, Bazel does not place config.json alongside the srcs.

Is there a way to tell Bazel where to place the file?

Or perhaps I need to copy each source-file alongside the config?

sdgfsdh
  • 33,689
  • 26
  • 132
  • 245
  • Can you tell the compiler what file to use for the config? If you can pass something like `--config=...` then it seems pretty easy to make this work. This is may also be important because if the compiler requires the file to be named exactly `config.json` by default, then as written `config_file = ctx.actions.declare_file("config.json")` means you can only ever have 1 `foo_library` per `BUILD` file, otherwise the outputs will conflict (bazel will throw an error like `file 'config.json is generated by these conflicting actions`). With the flag, you could have multiple config files and targets. – ahumesky Jul 25 '22 at 16:26

1 Answers1

0

You can do this with ctx.actions.symlink e.g.

srcs = []

# Declare a symlink for each src files in the same directory as the declared
# config file.Then write that symlink.
for f in ctx.files.srcs:
    src = ctx.actions.declare_file(f.basename)
    srcs.append(src)
    ctx.actions.symlink(
        output = src,
        target_file = f,
    )

config_file = ctx.actions.declare_file("config.json")
ctx.actions.write(
    output = config_file,
    content = json_for_srcs(ctx.files.srcs),
)

# Run compiler
ctx.actions.run(
    inputs = srcs + [config_file],
    outputs = # TODO: Up to you,
    tools = [ctx.file.__compiler], #TODO: Update this to match your rule.
    command = ctx.file.__compiler.path,
    args = ["."],
    #...
)

Note that when you return your provider that you should only return the result of your compilation not the srcs. Otherwise, you'll likely run into problems with duplicate outputs.

silvergasp
  • 1,517
  • 12
  • 23