Up

5.1  Practical hints for using OCaml (mostly Unix-specific)

Making the most common tasks of programming as simple as possible is a necessity for productive work. Therefore, I have devoted some time to reducing development cycles for the particular environment (Unix) that I usually work in, i.e. command-line oriented software development as opposed to integrated development environments (IDEs). The following hints might help you get started with OCaml-development if you prefer similar environments as I do.

5.1.1  Automating building and installation of software with OCamlMakefile

Most approaches to automating the build-process are usually a bit heavy-weight and aim at larger projects. Still, it is much more likely that a project consists of only a couple of files which do not need specialized treatment. This is the rationale behind the development of OCamlMakefile: it tries to minimize the maintenance effort as far as possible while still scaling up fairly well to projects of medium complexity.

Take a look at its README to get an impression of its features. Here is a nice example of such a Makefile. Especially beginners should find it much easier getting started with a tool that incrementally compiles their project files in the correct order without much hassle.

5.1.2  Using the Vim-editor with OCaml

If you prefer Emacs, just skip this section ;-)

Recent versions of the famous VIM-editor come with a wealth of features that make program development fun, the most important ones being:

If you want to configure VIM in a similar way as I do, just merge any wanted settings from my configuration files with yours or copy them if necessary: my .vimrc and my .vim-directory. The latter also contains the most recent versions of the syntax-, indent and filetype (ftplugin) files which I maintain in case you want to stay at the bleeding edge. I send updates to the VIM-maintainers at a regular basis.

Use the help-system of VIM to learn about any options you do not yet know. The following additional explanations should be noted:

5.1.3  Creating and using customized toplevels for scripting

An often asked question on the OCaml-list1 concerns the creation of toplevels (interpreters) which depend on C-libraries. This is necessary, for example, to make the often needed Unix-library available. Additionally, it is a prerequisite for scripting, because the standard toplevel is itself interpreted, which precludes its use as a script interpreter on Unix-systems due to security considerations: only true binaries can be mentioned as interpreters in script headers.

To create a toplevel interpreter usable for scripting, we need the -custom-option, e.g.:

# ocamlmktop -custom -o mocaml

This will create a standard interpreter mocaml in the current directory, but due to the -custom-flag it is suitable as a script interpreter. You will usually want to have it in some fixed binary directory, but for now we leave it in the home directory. Let’s write the following script mocaml_test (substituting your home directory for mine, of course):

#!/home/mmottl/mocaml

print_endline "Hello world!"

Making it executable (chmod 755 mocaml_test) and running it will lead to the intended result.

To give us a bit more functionality for scripting, it is often useful to create “fat” toplevels, which link against a lot of extra libraries, e.g. (maybe a bit overkill):

# ocamlmktop \
    -custom \
    -o mocaml \
    graphics.cma \
    nums.cma \
    unix.cma \
    str.cma \
    bigarray.cma \
    dbm.cma \
    -thread threads.cma

This allows us to execute a large number of OCaml-files directly, e.g.:

#!/home/mmottl/mocaml

let _ =
  Graphics.open_graph "";
  let sx, sy = Graphics.size_x (), Graphics.size_y () in
  let maxr = min (sx / 4) (sy / 4) and maxc = 256 in
  while not (Graphics.key_pressed ()) do
    let x, y, r, color =
      Random.int sx, Random.int sy, Random.int maxr,
      Graphics.rgb (Random.int maxc) (Random.int maxc) (Random.int maxc) in
    Graphics.set_color color; Graphics.fill_circle x y r
  done

Sometimes we will want to use modules in libraries which are located in directories other than the OCaml-default directory. For instance, let’s add support for the Unix-library and Pcre, which you may have installed in a subdirectory contrib of your OCaml-library path:

# ocamlmktop -custom -o mocaml -I +contrib unix.cma pcre.cma

In order to refer to this library, we will have to add its directory to the search path used by the interpreter. A convenient way to do this is to place a #directory-directive in the script, e.g.:

#!/home/mmottl/mocaml

#directory "+contrib"

let _ =
  let ic = Unix.open_process_in "/bin/df"
  and free, occu = ref 0.0, ref 0.0 in
  ignore (input_line ic);
  Pcre.foreach_line ~ic (fun line ->
    match Pcre.split line with
    | _ :: _ :: o :: f :: _ ->
        occu := !occu +. float_of_string o;
        free := !free +. float_of_string f
    | _ -> failwith "Strange ’df’-output!");
  Printf.printf "There are %.2f MB free and %.2f MB occupied"
    (!free /. 1024.0) (!occu /. 1024.0);
  print_newline ()

Since OCaml already supports dynamic loading of C-libraries on many platforms, an alternative is to just create a “plain” custom toplevel as described at the beginning of this section, without linking against all those large libraries. We can then load libraries on demand as follows (otherwise same example as above):

#!/home/mmottl/mocaml

#directory "+contrib"
#load "unix.cma"
#load "pcre.cma"

let _ =
  let ic = Unix.open_process_in "/bin/df"
  and free, occu = ref 0.0, ref 0.0 in
  ignore (input_line ic);
  Pcre.foreach_line ~ic (fun line ->
    match Pcre.split line with
    | _ :: _ :: o :: f :: _ ->
        occu := !occu +. float_of_string o;
        free := !free +. float_of_string f
    | _ -> failwith "Strange ’df’-output!");
  Printf.printf "There are %.2f MB free and %.2f MB occupied"
    (!free /. 1024.0) (!occu /. 1024.0);
  print_newline ()

I hope this information is enough to get you started with OCaml as a scripting language … have fun!


1
caml-list@pauillac.inria.fr

Copyright   ©  2008  Markus Mottl  ⟨markus.mottl@gmail.com
Up