Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 265
ReneSun Avatar asked Dec 06 '25 02:12

ReneSun


1 Answers

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.

like image 53
Brian Silverman Avatar answered Dec 10 '25 09:12

Brian Silverman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!