Module ... is used in several stanzas

I’ve written a bunch of ml files that I’d like to pull together into multiple executables that pipeline together nicely because they share types defined in one ml file. Dune firstly objects to multiple executables, then says I must add “modules” which I have done but it still doesn’t compile because one module is shared (the type definitions). So I made a library with separate “modules” sections for each of the library and executables but the error is the same.

What am I supposed to do?

Something like this in src/bin/dune

(executables
 (package example)
 (names my_exe1 my_exe2)
 (public_names my_exe1 my_exe2)
 (libraries my_lib)
 )

and something like this in src/lib/dune

(library
 (name my_lib)
 (public_name my_lib)
 (libraries cmdliner)
)

Should do the trick.

The separate library might not be necessary:

(executables
 (names x y z))

might work just fine and x, y, and z are permitted to have shared modules.

So I made a library with separate “modules” sections for each of the library and executables but the error is the same.

I’m not sure what error you’re referring to here, but it helps to keep the following rule in mind:

  • If you maintain only a single stanza (library, executable, etc) per directory, then you will never have to write modules fields explicitly.

Dune only complains when it cannot make an assignment from modules to stanzas all by itself. Dune does not permit a single module to belong to more than one stanza.

Thanks for the suggestions. My version of dune (3.0.2) rejects “names” and “public_names”. What am I doing wrong?

Post your dune file.

My bad. I hadn’t pluralized “executable”. Thanks!

I’m confused, these two sentences seem contradictory to me:

might work just fine and x , y , and z are permitted to have shared modules.

Dune does not permit a single module to belong to more than one stanza.

What am I understanding wrong?

You may be misunderstanding this bit, taken from the dune docs

  • (modules <modules>) specifies what modules are part of the library. By default, Dune will use all the .ml/.re files in the same directory as the dune file. This includes ones present in the file system as well as ones generated by user rules. You can restrict this list by using a (modules <modules>) field. <modules> uses the Ordered Set Language, where elements are module names and don’t need to start with an uppercase letter. For instance, to exclude module Foo , use (modules (:standard \ foo))

So by default Dune uses all ml files in the same directory as the dune file. If you have only a single stanza per directory, it will be fine because no module in that directory is shared across stanzas in that dune file.

If your source directory looks like this,

bin
-- dune
-- hello.ml
-- goodbye.ml
-- shared.ml
-- math.ml

and you’re dune file looks like this:

(executables
  (names hello goodbye))

It is fine…Shared and Math can be used by the others. But if your dune filed looks like this:

(executables
  (names hello goodbye)
  (libraries cool_lib))

(library 
  (name cool_lib))

It will not work…you will get an error about modules being used in several stanzas (ie two stanzas here). You fix it a couple of ways. Sticking with the first thing is fine. Or by restricting the modules used for each stanza with modules like this:

(executables
 (names hello goodbye)
 (modules
  ;; Ignore the math and shared modules in this stanza
  (:standard \ math shared))
 (libraries cool_lib))

(library
 (name cool_lib)
 ;; Only use math and shared modules in this stanza
 (modules math shared))

Or by putting library code in a separate directory with its own dune file.

bin/
-- dune
-- hello.ml
-- goodbye.ml

lib/
-- dune
-- math.ml
-- shared.ml

With this method, bin/dune is just one stanza

(executables
  (names hello goodbye)
  (libraries cool_lib))

and lib/dune is also one stanza

(library 
  (name cool_lib))

and you will be okay.

4 Likes

Thank you for the detailed answer. In addition to that, if I understand correctly, there is no way a module can be shared by two public libraries.
So the only way to have two public libraries depend on the same module is to put that module in a library that is also public.

So the only way to have two public libraries depend on the same module is to put that module in a library that is also public.

I think so. If you try to depend on a private library from a public library, you get an error like this:

4 |  (libraries unicorn))
                ^^^^^^^
Error: Library "unicorn" is private, it cannot be a dependency of a public
library. You need to give "unicorn" a public name.

(In this case unicorn is a private library that I tried to include in the dune file specifying a different public library in the same package.)

Thank you for your answers.