Is there a better technique to copy `cmi` files using dune?

Recently I have been working on making toplevels that run on browsers. There is a need to pack cmi files for merlin. It is conventional to use ppx_blob for the heavy lifting to actually pack the contents of the cmi files in the final js bundle, but before doing that, my building convention requires gathering the cmi files to a build folder first. I ended up with the following solution:

(rule
 (target re.cmi)
 (deps (package re))
 (action
  (progn
   (copy %{lib:re:re.cmi} re.cmi)
   (copy %{lib:re:re__.cmi} re__.cmi)
   (copy %{lib:re:re__Posix.cmi} re__Posix.cmi)
   ;; ... 13 more entries omitted for brevity
  )))

As you can see, the above stanza attempts to copy the cmi files of the re library. But there are clearly a couple of drawbacks of this approach:

  1. you have to manually list all cmi files that you want to copy
  2. only re.cmi is listed as the target, so in the situation e.g. re__Str.cmi is modified alone, the new version won’t be copied over during a dune build

I have tried around the glob syntax, without any luck. An intuitive alternative to this would be something like this:

(copy_files %{lib:re:re*.cmi})

But apparently the re*.cmi part is not interpreted as a glob spec.

The second drawback could be solved by (potentially generating) listing all files being copied as the rule’s target, but it’s just more redundancy. The core part to this problem is how to (or if we can) glob the cmi files. So my question is: Is there any way that I can automate the enumeration of library cmi files?

By the way, another question

(I am posting it here since it’s related to the above question enough not worthy to post as a separate topic IMO)

Another question is, when I tried to copy the cmi file of an internal library (i.e. a dune library in the same project as the cmi packing logic), it seems that the cmi file is not considered as part of the library artifact and I have to include something like the following to be able to use %{cmi:camlrepl_pervasives/camlrepl_pervasives} at another dune file.

(rule
 (target camlrepl_pervasives.cmi)
 (deps camlrepl_pervasives.cma)
 (action (copy %{cmi:camlrepl_pervasives} %{target})))

;; for the following library stanza
(library
 (name camlrepl_pervasives)
 ;; ... the rest omitted for brevity
)

Otherwise, looking at the _build folder, the cmi file will not be copied to ../camlrepl_pervasives (the src folder) from ../camlrepl_pervasives/.camlrepl_pervasives.objs/byte.

I am not sure whether this is by design or a bug, and whether I am doing things right. Any suggestions / pointers are highly appreciated.

1 Like