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, call Namespaces.handler before or
after your hook that you pass to dispatch.
If using OASIS, find the bottom of your myocamlbuild.ml file, and replace
the call to dispatch 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 in src/ 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.
41 commits
1 commits
OCaml
97.9%
Makefile
2.1%
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, call Namespaces.handler before or
after your hook that you pass to dispatch.
If using OASIS, find the bottom of your myocamlbuild.ml file, and replace
the call to dispatch 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 in src/ 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.
41 commits
1 commits
OCaml
97.9%
Makefile
2.1%