Creating generic rules in dune

I have a dune file where I have several rules of the form

(rule
  (target lambda.ml)
  (deps lambda.sk)
  (action (run necro-ml -o %{target} %{deps})))

where only the name lambda changes. Is it possible to write a generic %.sk → %.ml rule?

I looked at the docs and could not find it. And please let me know if this forum is not the right place to ask this.

It used to be impossible (don’t know if this has changed) but you can work around it by using the ocaml syntax feature of dune to generate the dune files on the fly

I confirm this is not currently possible. The alternatives, depending on your use-case, are 1) use OCaml syntax, 2) use a generated dune files with (include ...).

This feature is something that people have asked for in the past and is definitely in the radar of the development team, but we want to make sure to get the design right, and that may take some time.

Cheers,
Nicolás

2 Likes

I agree that using the concept of generated dune files by the help of dune’s (include …) stanza won’t disappoint because we’ve used it in some area in odoc (#665) and it has worked. Feel free to look into it, and I’ll be happy to guide you where you need to :slightly_smiling_face:.

1 Like

Is it possible to write a generic %.sk → %.ml rule?

This is one of the reasons why I use mk instead of dune:

%.ml: %.sk
	necro-ml -o $target $prereq

Thank you for the suggestions. I think we will be maintaining things manually for the moment, because:

  1. OCaml syntax may go away “It is not clear whether the OCaml syntax will be supported in the long term as it doesn’t work well with incremental builds.”
  2. include cannot be used with a generated file “Currently, the included file cannot be generated and must be present in the source tree.”

I tried understanding @lubegasimon’s solution, but the linked PR has 750 files changed, and I don’t know where I should look.

Yes, this means you need to commit the generated dune files into your repository, but depending on your use-case this may be better than mantaining the files by hand (for example if you have a lot of rules to generate). Also you can use dune's promote machinery to handle changes to the generated files, which is handy.

If you want to give it a try, the simplest possible way to use this is as follows:

;; This rule generates the dune file, you should replace `...` by
;; a suitable action.
(rule
 (mode promote)
 (action (with-stdout-to dune.inc (run ...))))

;; This includes the actual generated dune file; note that
;; it must exist in the source tree (so it must be committed with the repository).
(include dune.inc)

If you want to use dune's promote machinery to have better control of the changes in the generated files, you can modify things a bit as follows:

;; Note the different file name `dune.inc.gen`.
(rule (with-stdout-to dune.inc.gen (run ...)))

;; You can use `dune build @gen` to see the diff in the generated file,
;; and `dune promote` to accept it.
(rule
 (alias gen)
 (action (diff dune.inc dune.inc.gen)))

(include dune.inc)

Hope it helps,
Nicolás

2 Likes

I tried understanding @lubegasimon’s solution, but the linked PR has 750 files changed, and I don’t know where I should look.

You surely don’t need to look into all the files (sorry for being unclear). From the perspective of your example, you just need to look into gen_link.ml, its corresponding dune-file. The generated dune file is link.dune.inc (Note: link.dune.inc should already be existing, it is expected to be empty before the first build. It should be on the same level with dune-file you’re including it, for example dune-file).

The commands in the generated link.dune.inc are in favour of odoc aiming at generating .odocl which we invoke on for example odoc html-generate ... to generate html files, and odoc html-targets … to take a glimpse at the expected html target to be generated. For more about odoc invocation, run odoc --help in your shell.

I hope this shades more light to unblock you, regardless, don’t hesitate to ask for more clarification, I’m happy to clarify.

1 Like

Thank you for the detailed description. If I read the documentation correctly, mode promote means always run the rule, independently of the presence of the file. Is this correct?

Thank you, that makes sense now.

1 Like

The rule is always run, but the generated file is left in the _build directory. (mode promote) means that the generated file will always be copied over the file in your working directory.

Cheers,
Nicolás

1 Like