The OCaml Ecosystem

The OCaml ecosystem is not monolithic: the compiler and tools are not maintained by the same entities. As such, it can be difficult to understand the history and roles of the various pieces of this ecosystem. The goal of this page is to give a quick overview of the situation and the role that Dune plays in it.

The OCaml Compiler Distribution: Compiling and Linking

The OCaml compiler distribution contains “core” tools including the compilers (ocamlc and ocamlopt). They turn source files (with extensions .ml and .mli) into executables and libraries. Dependencies between compiled objects only exist at the module level, so this is a low-level tool.

Findlib: Metadata for Libraries

Findlib is a tool that defines the concept of library, so that libraries can depend on other libraries on top of the notion of module. Definitions of libraries, and other pieces of metadata, are stored in META files.

Findlib ships an executable named ocamlfind that can be used as a wrapper on top of the compilers to perform tasks such as producing an executable from compiled object files and external libraries.

Opam: a Collection of Software Projects

Opam is a package manager. It is used to determine which packages are necessary, and how to fetch and build them. Packages can contain libraries, executables, and other kinds of files.

The notion of version is specific to opam. If your project uses a function named Png.read_file but this function has been added only in version 1.2.0 of that package, opam needs to know about it.

Opam manages collections of installed packages, called switches. Using your project’s dependencies (names and version constraints), it is able to create a switch that you’ll be using to develop your project.

Public definitions of packages are available in a database called opam-repository which is maintained as a public Git repository. Publishing a package on opam (to make sure that external users can use your project) consists in adding its definition to opam-repository.

Dune: Giving Structure to Your Source Tree

Dune is a build system. It is used to orchestrate the compilation of source files into executables and libraries.

Assuming you have a development switch set up, you communicate to Dune about how your project is organized in terms of executables, libraries, and tests. It is then able to assemble the source files of your projects, with the dependencies installed in an opam switch, to create compiled assets for your project.

How Dune Integrates With the Ecosystem

Dune is designed to integrate with the tools mentioned above:

  • By knowing how the OCaml compilers operate, it knows which build commands should be re-executed if some source files change.

  • It outputs metadata like dependency information into META files that Findlib is able to make use of. This ensures that even if a project does not use Dune, it can use a library that has been produced by Dune. Conversely, it can read these files to determine dependency information for dependencies that have not been produced by Dune.

  • It is able to generate opam files with filenames consistent with how opam looks for them. The generated files use build commands that make use of the @install and @runtest aliases so that the Dune abstractions map to the opam ones.

Dune is Opinionated

As described above, the OCaml ecosystem does not have a centralized toolchain. Units such as modules, libraries, and packages operate at different levels, and the relation between these can be confusing to users.

Dune tries to simplify the picture by reducing the difference between these objects:

  • By default, a library will only expose a single top-level module named after the library (this is called a wrapped library).

  • A library can only be installed in the package of the same name. This means that the names found in dune-project and opam files (package names) are consistent with the names found in dune files (library names). More precisely, libraries foo, foo.bar and foo.baz are part of the foo package.