File Generation Last updated May 4, 2022

Generating files is easy in Bazel. No Obazl-specific rules are needed to generate files and integrate them into your OCaml build. There are two techniques you can use: genrule and a custom template rule.

genrule

Rule genrule (for "general rule") provides a means of integrating shell scripts into Bazel’s hermitic build ecosystem. In addition to passing the script via the cmd attribute, you must pass all inputs (files and tools) and outputs, in accordance with the general Bazel requirement. That’s what allows Bazel to add your script to the dependency graph, so as to ensure a reproducible build.

Example from demos/ppx/genrule:

genrule(
    name = "transform",
    srcs = ["hello.ml"],
    ## due to filename->module_name rules, output must be hello.ml, not e.g. hello.pp.ml
    outs = ["tmp/hello.ml"],
    tools = [":_ppx.exe"],
    ## $(location :_ppx.exe) resolves to wherever Bazel placed _ppx.exe.
    ## $< is the input file; $@ is the output file.
    cmd = "$(location :_ppx.exe) -dump-ast $< > $@"
)

This genrule runs a PPX executable (:_ppx.exe) to transform input hello.ml, placing the output in tmp/hello.ml. The ":_ppx.exe" label refers to the ppx_executable target that produces the executable; $(location :ppx.exe) is a Bazel-specific construct that resolves to the file-system location of the file produced by :_ppx.exe (which could be anywhere).

Emitting multiple files is a little more complicated. See the genrule documentation for more information.

To depend on a file produced by genrule, you can use the label of the outs file. You do not have to use the name of the rule.

Custom template rules

Bazel supports a rudimentary templating functionality via the expand_template action. To use this you must write a custom rule; fortunately that is not terribly difficult to do. Describing how is beyond the scope of this manual, but you can find a simple example with extensive comments at demos/filegen/template.