ReneSun
ReneSun

Reputation: 33

BAZEL + bash: execute bash/python script to do code generation and use them in bazel system

I am new to Bazel. I have a project which is built with Bazel. But some of the source files are pre-codegened and then compile them with Bazel. Now I can run the bash script standalone and run the bazel command:

.
|-- project
|   |-- BUILD (will depend on temp_output:codegen)
|   |-- scripts
|   |   |-- codegen.sh (read config.yaml and generate codegen.cpp/hpp and a BUILD.bazel)
|   |-- config
|   |   |-- config.yaml
|   |-- temp_output
|   |   |-- codegen.cpp (not existed before running codegen.sh)
|   |   |-- codegen.hpp (not existed before running codegen.sh)
|   |   |-- BAZEL.build (not existed before running codegen.sh)
|-- WORKSPACE



$ ./scripts/codegen.sh
$ bazel build :project

What are done in the codegen.sh:

  1. Read the config.yaml where the contains some other WORKSPACE path and name.
  2. Query the targets in that WORKSPACE.
  3. Create cpp/hpp files to include some headers files.
  4. Create a new BUILD file, adding the depends on those targets.

My goal is to embed the bash script in the bazel system. I tried with rule + action.run. But the failures are for:

  1. sandbox directory is not readable nor writable.
  2. input files cannot be found in sandbox.

Is there a fancy way to do this? Or any examples I can refer to?

Upvotes: 3

Views: 5327

Answers (1)

Brian Silverman
Brian Silverman

Reputation: 3868

The simple way to do this is with genrule. Something like this in project/BUILD:

genrule(
    name = "run_codegen",
    srcs = [
        "codegen.sh",
        "config.yaml",
    ],
    outs = [
        "codegen.cpp",
        "codegen.hpp",
    ],
    cmd = "$(location codegen.sh) --config $(location config.yaml) --cpp $(location codegen.cpp) --hpp $(location codegen.hpp)",
)

cc_library(
    name = "codegen",
    hdrs = [ "codegen.hpp" ],
    srcs = [ "codegen.cpp" ],
)

Some things to note:

  • Using $(location) to get the paths for the input and output files. If the script uses relative paths, I'd modify it to take the paths as arguments, or write a wrapper script that creates a temporary directory and moves things to/from there based on flags. The only other reliable way to create paths is with "make" variables, but those are generally harder to work with and more brittle with respect to modifications to the genrule.
  • Not generating a BUILD file. You can only do this from a repository rule, and it gets significantly more complicated. I don't think you need to for this use case, just write the rule in project/BUILD.

If you want to embed this in a rule instead of using genrule for some reason, make sure you're using File.path to get all the paths to embed in the command. That's the equivalent of $(location). It's hard to be more specific about why your rule doesn't work without seeing a copy of it.

Upvotes: 1

Related Questions