Suppose I have a set of modules each of which being rather "bushy" with submodules.
M1.X M2.X M3.X
M1.Y M2.Y M3.Y
M1.Z M2.Z M3.Z
M1.W M2.W M3.W
M1.Q M2.Q M3.Q
M1.P M2.P M3.P
Moreover, I'd like each of these bushes to sit under one master module.
Home.M1
Home.M2
Home.M3
Now, it's easy to structure the project directory for each of M1
, M2
, and M3
using Oasis' Pack:
option. In particular, what I like and am trying to solve for is (a) the ability to lay out my files in the standard .ml
/.mli
format and (b) having ocamldoc
produce properly linked documentation.
But since I'd like to distribute each of M1
, M2
, and M3
in the same library under a common module hierarchy I cannot use Pack:
and am instead forced to throw the whole damn thing into a single file in order to (a) not accidentally clobber the global namespace, (b) not accidentally proliferate modules all over the Home.
namespace which are not intended to be used directly, and (c) not ruin ocamldoc linking.
So my question is, subject to the goals suggested above, how can I use Oasis to create a package with hierarchical modules of this form?
Some additional constraints include:
- It is no accident that the modules under the
M1.
,M2.
, andM3.
namespaces conflict---this occurs in the genuine situation as well! - The modules in the
M2.
andM3.
namespace depend upon the modules in theM1.
namespace.
My preference would be able to arrive at a solution which also allows a sensible file layout, e.g.
src -+
+-- m1 -+
| +-- x.ml
| +-- x.mli
| +-- y.ml
| +-- y.mli
| +-- z.ml
| +-- z.mli
| |
| ...
|
|
+-- m2 -+
| +-- x.ml
| +-- x.mli
| +-- y.ml
| +-- y.mli
| +-- z.ml
| +-- z.mli
| |
| ...
|
|
+-- m3 -+
+-- x.ml
+-- x.mli
+-- y.ml
+-- y.mli
+-- z.ml
+-- z.mli
|
...
It may also be possible that this is impossible with Oasis. In such a case, suggestions as to how to use other build tools are acceptable and welcome. Assume I have very little understanding of the other tools... because it's probably true!
With oasis
The
pack
inoasis
is a little bit broken, as it clobbers the namespace by including all paths into the search path. There is a long-living accepted bug request, but things are still where they are. But, if it worked correctly, it can help you, since it will create a library namespaces, allowing you to have modules with the same name in different folder. But, it doesn't work, so we should forget about it.The approach we have taken in BAP project was to mangle all module names with ugly
bap_subproject_
prefix, that protects us from conflicts with our own modules, as well as from conflicts coming from external libraries. For eachbap_subproject
we have a folder with all implementation modules with mangled names and one umbrella module to rule them all. This module is stored in filebap_subproject.ml
where it defines aliases for all modules and types that it is going to export. Usually it contains entries like:There is also a big
Bap
project, that unites all sublibraries under one namespaceBap.Std
, and reexports everything it needs, so that after oneopen Bap.Std
you have and access toInsn
module that is defined inbap_disasm/bap_disasm_insn.ml[i]
Without oasis
Disclaimer: this solution may still work with oasis if you extend it with plugin.
We've used this approach in one project, that is unfortunately closed source, so I can't provide a link. Each subproject lives in its own subfolder, within it own namespace (we have had
parser
module in each subfolder, without any clobber). For each subproject there is anmlpack
file, in thetop
folder:The contents of the
expr.mlpack
is:ocamlbuild
sees thisexpr.mlpack
as a standalone module that hasLexer
,Parser
, etc submodules defined in it (and accessible as, e.g.,Expr.Lexer
). And there is no conflicts with a sibling project that also hasLexer
, as well as no conflicts withocaml-libs
or any other externalLexer
, since theexpr
folder is actually never included into the search path.If you need to add yet another layer to your system, like a pack for packs, then you have three choices:
mlpack
ormllib
files pointing to a child folder.big.mlpack
that references all toplevelmlpack
'ed modulesbig.ml
that reintroduces all modules.Last two approaches requires top-level packed modules to have different names of course. But usually this is fair enough.