Introduction

Note: OCaml is installed on the Linuxlab cluster.

Finding the right mix of tools to edit, compile, and debug programming
projects can be a frustrating challenge. I’m going to discuss the
setup I use and recommend for developing with OCaml.

Within the past few years, OCaml has become an especially appealing
language for functional programming because of its growing tooling
support. Its predecessor,
Standard ML, was a well
designed and useful research language, but developing large projects in
it was troublesome because there wasn’t a set of standard tools and
libraries within the community (e.g., SML/NJ
provided its own build system, mosml and
MLton were two separate optimizing compilers).
Additionally, the user community was relatively small and it lacked
the support of libraries and packages that have become essential
components of other communities.

However, with a larger open source community and more commercial
backing (e.g.,
Jane Street Capital), OCaml
has acquired a mature set of tools to ease development.

The foundations of my toolchain are:

  • The
    OPAM
    package manager, for managing different versions of OCaml and
    associated sets of packages.

  • OCamlBuild (ocamlbuild) for compiling OCaml projects and greatly
    simplifying Makefiles.

  • taureg-mode as a mode for emacs, and associated mode for vim.

  • Merlin, which turns emacs and vim into tools closer to IDEs for
    OCaml.

Quick start

Clone
this git repo and
follow along.

OPAM

OPAM is a package manager for OCaml, similar to RVM.
It allows us to maintain multiple versions of OCaml compilers, along
with packages that work with them. It includes a large set of
libraries and makes them easy to install.

Installation instructions for OPAM can be found
here. OPAM supports many
package management systems, so you should be able to install it via
apt-get, brew, or whichever you use. If you’re using a Mac, I
recommand using the Homebrew management system.
There are also options for MacPorts as well. If you’re not using
either of these systems, I’d recommend installing Homebrew first, but
there are other options listed on OPAM’s install page (including
installing from source). I agree that it’s a pain to install a
package manager to install another package manager, but it gets better
once its installed!

Once you’re up and running you should be able to use the command opam init, which will initialize your opam installation.
This page gives some basic
uses for OPAM, but the big ones are:

  • opam switch for switching between versions. I usually switch
    into the main version I use and do all of my development with
    that. The only real reason to switch between versions is if you
    depend on a feature that exists in a certain version of OCaml.
    You will rarely run into this unless you use very cutting edge
    features of the type system.

    The output of opam switch will list a set of compilers available
    for you:

    system        I system        System compiler (4.00.1)
    4.03.0+trunk  I 4.03.0+trunk  latest trunk snapshot
    4.02.1        C 4.02.1        Official 4.02.1 release
    4.01.0        I 4.01.0        Official 4.01.0 release
    --           -- 3.11.2        Official 3.11.2 release
    --           -- 3.12.1        Official 3.12.1 release
    --           -- 4.00.0        Official 4.00.0 release
    --           -- 4.00.1        Official 4.00.1 release
    --           -- 4.02.0        Official 4.02.0 release
    

    With your current one listed. You can switch to another compiler
    (and the set of packages you’ve installed for it) by specifying
    the version after the switch. Note that you’ll have to run

    eval `opam config env`
    

    After switching. This updates your environment variables so that
    commands such as ocamlc or ocamlopt (the compiler) point at
    the versions you intend to use.

  • opam list lists the set of packages you have installed.

  • opam install allows you to install a package. As an example, if
    I wanted to use Jane Street’s core library (which provides a
    large set of utilities extending the standard library and useful
    for day to day programming) I would do

    Kristophers-MacBook-Pro-2:~ micinski$ opam install core
    The following actions will be performed:
    - install   comparelib.109.60.00
    [required by core]
    ...
    core_kernel.112.17.00
    [required by core]
    - install   core.112.17.00
    === 14 to install ===
    Do you want to continue ? [Y/n]
    

    And then type Y. core is very large and has a lot of
    dependencies. OPAM grabs all of these and installs them. (For me
    it took three minutes.)

I have a lot of luck with OPAM. No package management system is
perfect, but there are few times where packages fail to install. If
they do I usually look at the log files it leaves, and then ask for
help on a mailing list.

For CMSC330, we will try to use a minimal amount of external
packages. So don’t worry too much if you are having trouble with
OPAM. It does help, however, in making sure that the ocaml compiler
you’re using matches the one on the submit server.

For the class, I suggest installing OPAM as a way to install OCaml.

OCamlBuild

OCamlBuild
is a build manager for OCaml. It should be bundled with your OCaml
installation. It provides a fairly pushbutton way to build OCaml
projects. I personally find the user manual confusing and hard to
read, so I’ll reiterate the main things you need to know:

  • To compile a file, type ocamlbuild file.native. The .native
    extension builds native code using the optimizing compiler
    ocamlopt. You can also build bytecode versions.

  • To use packages and set up special parameters, you modify the
    _tags file in your project’s directory. The _tags file
    specifies package names, preprocessor options, etc…

  • Things get a little more complicated when you need to have a more
    involved build process (e.g., linking to external libraries). In
    these cases you can use OCamlBuild’s --help to figure out the
    right options, or read through the documentation.

  • Use a Makefile to call ocamlbuild with the right parameters so
    you can simply type make in your project’s directory as
    necessary (instead of remembering all of the options you need to
    pass). You can also write separate Make targets for tests,
    documentation, etc…

I’ve included an example use of OCamlBuild (and the _tags) file,
along with a Makefile which drives it, in the sample project below.

For CMSC 330, you won’t have to design build infrastructure: we will
provide boilerplate for each project. However, understanding how the
build process works may help demystify what’s going on.

Tuareg mode

Tuareg mode provides nice highlighting for emacs. Emacs modes
(libraries that extend emacs with extra behavior) are written in
[emacs lisp], a variant of the LISP family of programming
languages. Installing modes is fairly simple: you put them in a
directory (typically a subdirectory of ~/.emacs.d/) and modify your
~/.emacs file to point at the files.

You can obtain tuareg mode here or
here, if it’s not already
installed.

Merlin

Merlin provides two
features for developing OCaml that I find particularly helpful:

  • Intelligent type based completion

  • Error highlighting and feedback within an emacs buffer

Previously, my interaction method for working with OCaml was to write
some code, save all my files, run make, and find syntax errors.
This worked well enough, but it required a back-and-forth process for
getting rid of trivial (mostly syntax related) errors. Instead,
Merlin allows you to see errors as you type: it will underline and
highlight them in red every time you save. There are still some
errors it will miss (relating to problems involving multiple files or
modules), but I find it saves me a lot of time.

The Github page lists instructions for installing Merlin, but I
installed it via opam. You should be able to run opam install merlin. The installation will tell you how to modify your .emacs
file to set up merlin appropriately.

Note that to use Merlin, you need to tell it where your OCaml source
files are installed, along with what packages (libraries) you are
using. This will help it resolve references from other files. This
is easily specified in a .merlin file with a set commands that is
simple to use. I’m sure there are cases where it might not work
perfectly, but I have not run into them yet.

This guide
and
this guide
describe Merlin in more depth.

Merlin has a few key combinations that it adds to emacs, but I find
the most helpful one (and the only real one I use) is C-c C-x, which
jumps to the next error. There are also a few others relating to
completion, updating, etc… You can read about these in the
documentation. Merlin also has a very nice type sensitive code
completion facility (similar to IntelliSense) that may be worth the
time to set it up, if you so choose. For our projects in CMSC330, it
might be overkill: don’t stress about setting up your emacs
configuration if it is complicated.

Running make in emacs

If you’re using emacs, I suggest running make from within emacs so
that errors can be cross referenced directly from within emacs (rather
than having to switch tabs, write down the line number, and go back
and forth looking for errors).

To run make from within emacs, you can use the command M-x compile. Note that you’ll have to (or at least, I have to) switch
to the base directory to your project’s home. I simply set the
compile command to cd /path/to/project; make, but this can
easily be customized

Setting up and developing a project

My typical workflow for developing projects is the following:

  • Make a new directory for the project.

  • Initialize a git repository within that directory and make an
    initial commit (along with a README file).

  • Set up a default main.ml file and put a function that does nothing
    inside of it.

  • Set up a Makefile that calls ocamlbuild for the binary (or
    bytecode versions).

  • Set up a .merlin file that includes the set of places where my
    code is and what libraries I’m using.

Now, when I want to edit my project I use emacs and use the Merlin
keybindings. When I want to test my project and compile / run it, I
do so by going to a new terminal running make, and then running
main.native with the necessary parameters (or perhaps via a script).

Additional reading

This tutorial
is well written and should help fill any holes here.

Example project

I have set up
this example project
on Github that highlights the use of OCamlBuild, make, and Merlin.
For the projects in our class, I have given them boilerplate-structure
to work with Merlin. Let me know if projects aren’t working for you
and I will modify them as necessary.