You can install Dune using OPAM by running (in your system or a particular switch)
opam install dune
Writing a Dune File
Before we can use Dune to build our project, we need to tell Dune how to build it. We do so by writing a dune file. The dune file (named dune) should be in the directory of your project. We describe libraries, executables, tests, and other things Dune needs to know about. We write it in a syntax that Dune can read.
A dune file has different sections called stanzas. Common stanzas are:
- executable or executables: The executable stanza is used to describe an executable. The format of executable stanzas is as follows:
(executable (name <name>) <optional-fields> )
<name> is a module name that contains the main entry point of the executable. There can be additional modules in the current directory, you only need to specify the entry point.
- library: The library stanza is used to describe OCaml libraries. The format of library stanzas is as follows:
(library (name <library-name>) <optional-fields> )
As you can see, the stanzas have similar formats. First, the name of the stanza. Then, the name and optional fields. Each stanza is in its own brackets and the contents in a stanza is indented.
Besides a dune file, you may have other files in your project’s directory. Common ones are:
- .ml files: implementation files end in ml. These include your main program, any module that you write etc.
- .mli files: interface files end in mli. These files provide the implementation details of a corresponding implementation (.ml) file. E.g., a module can be hidden by attaching an interface (also called signature or module type). And a module defined by a .ml file can be constrained by a signature placed in a .mli file of the same name. We’ll talk more about .mli files in the next post.
To build your project, run the following command in your project directory:
dune build name.exe
Then, run the executable with:
dune exec name.exe
I’ll take this tutorial as an example:
First, in your project’s directory (named todolist in the tutorial), there is a directory named bin. In it, a dune file with the following content:
(executable (name main) (libraries lib))
Note that this dune file only has one stanza: executable. In the executable stanza’s optional field, the library lib is specified as a dependency for the executable.
You may have a lib directory in your project directory. In there, a dune file with the following content:
(library (name lib))
This dune file only has one stanza: library. We’ve told dune that the library is called lib. It must be a valid OCaml module name but doesn’t need to start with a capital letter (remember, in OCaml, module names normally starts with a capital letter). In the directory lib, there can be multiple modules. It may have a module named Math. The math.ml file has the content of the module:
let add x y = x + y let sub x y = x - y
Going back to the dune file of the project above, main is specified as the entry point of the executable. main.ml may have the following content:
open Lib let () = let result = Math.add 2 3 in print_endline (string_of_int result); let result = Math.sub 3 1 in print_endline (string_of_int result)
Notice that first, we open Lib (with a capital L) so that all modules in it are available. Then, we call the function add and sub in the Math module by calling Math.add and Math.sub respectively.
To summarize, here is what’s in your project directory:
$ ls todolist/ bin lib (Sub-directories bin and lib.) $ ls todolist/bin/ dune main.ml (in /bin, the dune file with the executable stanza and the main program.) $ ls todolist/lib/ dune math.ml (in /lib, the dune file with the library stanza and the Math module.)
Finally, we build the project with:
dune build bin/main.exe
And we run the executable with:
dune exec bin/main.exe
And you can see the results of the program running!
In the next post I’ll do more fancy things with Dune. Stay tuned!