2

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?

ReneSun
  • 23
  • 2
  • 5

1 Answers1

1

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.

Brian Silverman
  • 3,085
  • 11
  • 13
  • Hi @Brian Thanks for your help. About the BUILD file, I have to create a new BUILD file. The content about the BUILD file is also codegen as well. – ReneSun Jan 04 '22 at 01:55
  • What parts of the BUILD file need to be generated? Depending on what parts need to change, there are ways to use custom rules instead. – Brian Silverman Jan 04 '22 at 02:54
  • Hi @Brian Silverman I tried the genrule. But failed. cc_library( name = "codegen", data = [":run_codegen"], ) genrule( name = "run_codegen", srcs = [ "codegen_test.sh", ], outs = [ "tmp_output.cpp", ], cmd = "$(location codegen_test.sh) $(location tmp_output.cpp)", ) I need to use codegen_test.sh to generate the tmp_output.cpp but it reported "bazel-out/k8-dbg/bin/tmp_output.cpp: No such file or directory". – ReneSun Jan 04 '22 at 03:34
  • Putting it in cc_library.data means the files in that rule can load the .cpp file at runtime, which is unusual. I think you want it in cc_library.srcs instead. Is codegen_test.sh changing to a different directory before trying to use that relative path maybe? – Brian Silverman Jan 04 '22 at 03:44
  • Hi Yes. It is because I changed to another path. Another question is that, during the codegen, I will call "cd $AnotherWORKSPACE; bazel query xxxx". And then I will do string split and figure out the codegen content. It seems I cannot call "bazel query" again in the script. – ReneSun Jan 04 '22 at 06:07
  • Looks like I don't have permission to run "bazel query" in the script. – ReneSun Jan 04 '22 at 06:50
  • Hi @Brian Silverman I found my issues can be solved by just adding one tags = "local". – ReneSun Jan 04 '22 at 13:34