This project is not supported for the time being. Similar behaviour may be
possible using codept v0.10's -nested
feature.
Ever wish src/server/foo.ml
was module Server.Foo
and not just Foo
?
Who likes to name it src/server/server_foo.ml
, just to avoid naming conflicts?
Namespaces is an Ocamlbuild plugin that turns directories in your source tree into scoped OCaml modules. You get a nice, logical, and predictable structure, and you don't have to worry about duplicate filenames anymore. It's the sane file naming convention that most other languages have always had.
If you have the directory structure on the left, you will get the OCaml modules on the right:
The module structure works as if you had written:
module Server =
struct
module Foo = (* server/foo.ml *)
module Bar = (* server/bar.ml *)
end
module Client =
struct
module Foo = (* client/foo.ml *)
module Bar = (* client/bar.ml *)
module Ui =
struct
module Reactive = (* client/ui/reactive.ml *)
end
include (* client/client.ml *)
end
There is no conflict between server/foo.ml
and client/foo.ml
, because there
is no globally-visible module Foo
.
Within a module, you don't have to (indeed, must not) qualify sibling module
names: from Server.Foo
, you access Server.Bar
as just Bar
. You can access
children and nephews, but cannot access parents.
The usual dependency restrictions between OCaml modules apply: there must not be any dependency cycles. Siblings, if they depend on each other, must depend on each other in some order, and each parent module depends on all of its child modules.
The modules are composed with -no-alias-deps
, so depending on a directory
module does not automatically pull in all of its descendants, unless they are
actually used. This also means that Namespaces requires OCaml 4.02 or higher.
-
Install Namespaces:
opam install namespaces
-
Add it to your build system.
-
If using Ocamlbuild, create
myocamlbuild.ml
, and make it look like this:let () = Ocamlbuild_plugin.dispatch Namespaces.handler
Invoke Ocamlbuild with:
ocamlbuild -use-ocamlfind -plugin-tag "package(namespaces)"
If you already have
myocamlbuild.ml
, callNamespaces.handler
before or after your hook that you pass todispatch
. -
If using OASIS, find the bottom of your
myocamlbuild.ml
file, and replace the call todispatch
with this:let () = dispatch (MyOCamlbuildBase.dispatch_combine [MyOCamlbuildBase.dispatch_default conf package_default; Namespaces.handler])
Then, add this to the top of your OASIS file:
OCamlVersion: >= 4.02 AlphaFeatures: ocamlbuild_more_args XOCamlbuildPluginTags: package(namespaces)
and re-run
oasis setup
.
-
-
Tag the directories that you want to become namespaces with the
namespace
tag. For example, to make all directories insrc/
into namespaces, you can add this to your_tags
file:<src/*/**>: namespace <src/**>: include
-
If you are building a library, see additional instructions in
manual.md
. See also that file if you have generated files in your project. -
Enjoy!
An Ocamlbuild plugin is by no means the best way, ideally, to deal with the problem of structuring modules in OCaml. I am releasing this, in part, to advance the discussion. My hope is that after some time, we will have a more conclusive solution integrated into the OCaml tool chain.
Namespaces is distributed under the terms of the 2-clause BSD license.