4

I wanted to make a BUILD rule that depends on a data file which is generated from other files. I tried to write something like this:

genrule(
    name = "data",
    outs = ["MyApp/data.dat"],
    cmd = "cd ../libpackfiles ; bazel run FilePacker $(PWD)/../apps/MyApp/data.dat $(PWD)/../apps/MyApp/dataFiles",
)

But it didn't work for many reasons. $(PWD) was not recognized by the genrule (the cmd works fine in an equivalent sh script). And I don't know if I am allowed to leave my workspace directory (which is called apps) to do another bazel run command like this.

How could I write a correct genrule that achieves what I want?

Thanks!

thinlizzy
  • 668
  • 8
  • 13

1 Answers1

6

Some things to keep in mind when writing genrules:

  1. A genrule needs to know all its input files and output files (srcs and outs attributes)
  2. It needs to know the tools it's going to use in the command (exec_tools attribute). These tools can be other things that need to be built, like binary targets (cc_binary, java_binary, sh_binary, py_binary, etc), or they can be pre-compiled binaries.
  3. The tools have to produce the same files that the genrule declares in the outs attribute. It's often easier to declare the files in the outs attribute and then pass the file names to the tool using $(OUTS) in the cmd attribute.

See the documentation for genrule, which includes some simple examples: https://docs.bazel.build/versions/master/be/general.html#genrule

It would look something like this:

genrule(
  name = "gen_data",
  srcs = [":dataFiles"],
  outs = ["data.dat"],
  exec_tools = ["//libpackfiles:FilePacker"],
  cmd = "$(location //libpackfiles:FilePacker) $(OUTS) $(SRCS)"
)

This assumes that :dataFiles is a filegroup target in the same BUILD file as the gen_data target which has a list of files of all the inputs you want to pack. Or it could be a filegroup target in a BUILD file in the dataFiles directory, in which case it would be something like //app/MyApp/dataFiles:dataFiles (and don't forget to set its visibility attribute to //visibility:public).

$(location //libpackfiles:FilePacker) is replaced with the file path of that target. $(OUTS) is replaced with all the files in the outs attribute, and similarly for $(SRCS).

ahumesky
  • 4,203
  • 8
  • 12
  • Thank you very much! I was able to rewrite my rule like this `genrule( name = "data", srcs = ["//TheBlackDarkSanctum/res"], outs = ["data.dat"], exec_tools = ["@libpackfiles//FilePacker"], cmd = "$(location @libpackfiles//FilePacker) $(OUTS) -files $(SRCS)", )` – thinlizzy May 12 '21 at 22:13