# Creating generic rules in dune

**URL:** <https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757>\
**Category:** Learning\
**Tags:** dune\
**Created:** [April 28, 2021, 3:15pm UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757 "2021-04-28T15:15:43Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![brab\_backup](https://avatars.discourse-cdn.com/v4/letter/b/bbce88/32.png) [@brab\_backup](https://discuss.ocaml.org/u/brab_backup)\
**Post date:** [April 28, 2021, 3:15pm UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/1 "2021-04-28T15:15:43Z")

</div>

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

```auto
(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.

---

<div class="post-metadata">

**Author:** ![mseri](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/mseri/32/91_2.png) [@mseri](https://discuss.ocaml.org/u/mseri)\
**Post date:** [April 28, 2021, 3:39pm UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/2 "2021-04-28T15:39:55Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [April 28, 2021, 3:42pm UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/3 "2021-04-28T15:42:49Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![lubegasimon](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lubegasimon/32/2185_2.png) [@lubegasimon](https://discuss.ocaml.org/u/lubegasimon)\
**Post date:** [April 29, 2021, 5:44am UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/4 "2021-04-29T05:44:38Z")

</div>

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](https://github.com/ocaml/odoc/pull/665)) and it has worked. Feel free to look into it, and I’ll be happy to guide you where you need to 🙂.

---

<div class="post-metadata">

**Author:** ![dromas](https://avatars.discourse-cdn.com/v4/letter/d/58f4c7/32.png) [@dromas](https://discuss.ocaml.org/u/dromas)\
**Post date:** [April 29, 2021, 8:42am UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/5 "2021-04-29T08:42:50Z")

</div>

> 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

```

---

<div class="post-metadata">

**Author:** ![brab\_backup](https://avatars.discourse-cdn.com/v4/letter/b/bbce88/32.png) [@brab\_backup](https://discuss.ocaml.org/u/brab_backup)\
**Post date:** [April 29, 2021, 9:05am UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/6 "2021-04-29T09:05:47Z")

</div>

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

1. [OCaml syntax](https://dune.readthedocs.io/en/latest/advanced-topics.html#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`](https://dune.readthedocs.io/en/latest/dune-files.html#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.

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [April 29, 2021, 9:38am UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/7 "2021-04-29T09:38:58Z")

</div>

> [@brab\_backup](#):
>
> [`include`](https://dune.readthedocs.io/en/latest/dune-files.html#include) cannot be used with a generated file “Currently, the included file cannot be generated and must be present in the source tree.”

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:

```auto
;; 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:

```auto
;; 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

---

<div class="post-metadata">

**Author:** ![lubegasimon](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/lubegasimon/32/2185_2.png) [@lubegasimon](https://discuss.ocaml.org/u/lubegasimon)\
**Post date:** [April 29, 2021, 10:02am UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/8 "2021-04-29T10:02:06Z")

</div>

> 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](https://github.com/ocaml/odoc/pull/665/commits/ee817f7ba577399abb58e677478d347f10d704aa?file-filters%5B%5D=.inc&file-filters%5B%5D=.ml&file-filters%5B%5D=No+extension#diff-d47768bba4ed31c53b59c9e971f8337eb2677b996f9f2aa9be359bc98e991f52), its corresponding [dune-file](https://github.com/ocaml/odoc/pull/665/commits/ee817f7ba577399abb58e677478d347f10d704aa?file-filters%5B%5D=.inc&file-filters%5B%5D=No+extension#diff-ba8732b7c8e7e13032639092acd49285ed63beab387041c0b296fd8edee07de0). The generated dune file is [link.dune.inc](https://github.com/ocaml/odoc/pull/665/commits/f16d4da7a19e494b04e1e9e89fcc7e01139be231#diff-46a565d875497c5e798caa862bdc15caaa45a20a2a42f48b808bb64ddd99cfef) (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](https://github.com/ocaml/odoc/pull/665/commits/ee817f7ba577399abb58e677478d347f10d704aa?file-filters%5B%5D=.inc&file-filters%5B%5D=No+extension#diff-0dd9d34b66313dcaac0b3d50f89655cc7eb242e5a45c34bcb004a661ddf48745)).

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.

---

<div class="post-metadata">

**Author:** ![brab\_backup](https://avatars.discourse-cdn.com/v4/letter/b/bbce88/32.png) [@brab\_backup](https://discuss.ocaml.org/u/brab_backup)\
**Post date:** [April 30, 2021, 7:50am UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/9 "2021-04-30T07:50:49Z")

</div>

Thank you for the detailed description. If I read [the documentation](https://dune.readthedocs.io/en/latest/dune-files.html#modes) correctly, `mode promote` means always run the rule, independently of the presence of the file. Is this correct?

---

<div class="post-metadata">

**Author:** ![brab\_backup](https://avatars.discourse-cdn.com/v4/letter/b/bbce88/32.png) [@brab\_backup](https://discuss.ocaml.org/u/brab_backup)\
**Post date:** [April 30, 2021, 7:52am UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/10 "2021-04-30T07:52:11Z")

</div>

Thank you, that makes sense now.

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [April 30, 2021, 8:07am UTC](https://discuss.ocaml.org/t/creating-generic-rules-in-dune/7757/11 "2021-04-30T08:07:20Z")

</div>

> [@brab\_backup](#):
>
> Thank you for the detailed description. If I read [the documentation](https://dune.readthedocs.io/en/latest/dune-files.html#modes) correctly, `mode promote` means always run the rule, independently of the presence of the file. Is this correct?

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
