Jbuilder: how to factor user defined rules

Imagine you are using atdgen to generate some json formaters. Defining an atgden building rules looks simple and concise

(rule
  ((targets (foo_t.mli foo_t.ml foo_j.mli foo_j.ml))
  (deps (foo.atd))
  (action (progn (run ${bin:atdgen} -j ${<}) (run ${bin:atdgen} -t ${<})))))

I understand that jbuilder requires listing all .atd files manually, and this is an acceptable tradeoff, but in the case you have say 20 .atd files, how to make it less verbose ? Copy-pasting this rules 20 times is ugly and you can easily end up with a 200 lines jbuild files.

Is there anyway to have “application/map” so that you could have a rule skeleton like (please forgive my lack of lisp syntax experience)

(rule foo 
  ((targets (${foo}_t.mli ${foo}_t.ml ${foo}_j.mli ${foo}_j.ml))
  (deps (${foo}.atd))
  (action (progn (run ${bin:atdgen} -j ${<}) (run ${bin:atdgen} -t ${<})))))

(map foo (file1 file2 file3 file4 file5))
2 Likes

This sounds like a case for the OCaml escape hatch where you can use OCaml in a jbuild file to generate a jbuild file. This would allow to generate the rules above concisely. It’s still a bit clumsy because the OCaml program needs to generate the complete file, not just the part for the rules above. Luckily, the program just generates text and does not cater to a complex API (as in ocamlbuild).

Thanks. This is indeed an easy solution.

On a more general note I believe it is unfortunate that we have to use “code generation” for simple rules like this, but I understand jbuilder is quite recent tool and has not reached the level of maturity required for every egde cases like this to be well supported.

Not only that, they warn people not to use the ‘OCaml escape hatch’.

The rule system really needs some love. We should be able to match on patterns, similarly to makefiles.