Dune: using the same name for a library and its main module without breaking auto wrapping

I’m writing a library that implements a data structure, let’s call it Foo. For obvious reason, an appropriate name for this library is “foo”, and an appropriate name for its main module is “Foo”. There are also some supporting modules “Bar” and “Baz”. I would like the following module hierarchy:

Foo      (* wrapper module *)
Foo.Foo  (* main module *)
Foo.Bar  (* supporting module *)
Foo.Baz  (* supporting module *)

This brings me to my question: is it possible in dune to use the same name for both a library and one of its modules, while still having dune syntheszie a wrapper module? By default, dune unfortunately currently assumes that the library is providing it’s own wrapper module as soon as there exists a module matching the name of the library.

An orthogonal question is, what might be a good workaround? I suppose I could rename the library to foolib… Has any one else run into this problem and how did you solved it? Thanks.

1 Like

One possibility is to write your wrapper module yourself:

module Foo = Foo_internal
module Bar = Bar
module Baz = Baz

This works with wrapped true (the default).

3 Likes

BTW, if this was a common pattern we could also add special support for this in Dune. Feel free to open a ticket on the Dune repository to track this issue.

1 Like

In a similar situation an approach I use is something along the lines of:

(library
 (name foo_)
 (public_name foo))

Then internally there are modules such as Foo_.Foo and Foo_.Bar. In my case I pass -open Foo_ to the compiler, so the mangled names aren’t so bad.

A less hacky approach would be welcome.

One solution I have been thinking of is to use a name that doesn’t clash with regular modules, such __init__.ml. Althought, that wouldn’t work when there are several libraries in the same directory. A more flexible solution would be to allow the user to choose the interface module:

(library
 (public_name foo)
 (interface_module _foo))

How would it work? It would include _foo in Foo. And add module aliases in Foo for all the other modules of the library?

Currently, foo.ml in library foo is compiled to foo.cm{i,o,x} while other files such as bar.ml are compiled to foo__Bar.cm{i,o,x} and a special foo__.ml file is generated to alias the long names to the short ones.

With (interface_module _foo), then foo.ml would to compiled just like any other module of the library, i.e. to foo__Foo.cm{i,o,x} and _foo.ml would be compiled to foo.cm{i,o,x},

I have the impression that it might be more confusing than the current situation. But I might be missing something.