The librarian (camllibr)

Mac:
This command is a MPW tool, not a standalone Macintosh application.

Overview

The camllibr program packs in one single file a set of bytecode object files (.zo files). The resulting file is also a bytecode object file and also has the .zo extension. It can be passed to the link phase of the camlc compiler in replacement of the original set of bytecode object files. That is, after running

        camllibr -o library.zo mod1.zo mod2.zo mod3.zi mod4.zo
all calls to the linker with the form
        camlc ... library.zo ...
are exactly equivalent to
        camlc ... mod1.zo mod2.zo mod3.zi mod4.zo ...

The typical use of camllibr is to build a library composed of several modules: this way, users of the library have only one .zo file to specify on the command line to camlc, instead of a bunch of .zo files, one per module contained in the library.

The linking phase of camlc is clever enough to discard the code corresponding to useless phrases: in particular, definitions for global variables that are never used after their definitions. Hence, there is no problem with putting many modules, even rarely used ones, into one single library: this will not result in bigger executables.

The usage for camllibr is:

        camllibr options file1.zo ... filen.zo
where file1.zo through filen.zo are the object files to pack together. The order in which these file names are presented on the command line is relevant: the compiled phrases contained in the library will be executed in that order. (Remember that it is a link-time error to refer to a global variable that has not yet been defined.)

Options

The following command-line options are recognized by camllibr.

-I directory
Add the given directory to the list of directories searched for the input .zo files. By default, the current directory is searched first, then the standard library directory. Directories added with -I are searched after the current directory, but before the standard library directory. When several directories are added with several -I options on the command line, these directories are searched from right to left (the rightmost directory is searched first, the leftmost is searched last).

-o library-name
Specify the name of the output file. The default is library.zo.

PC:
The following option is also supported:

@response-file
Process the files whose names are listed in file response-file, just as if these names appeared on the command line. File names in response-file are separated by blanks (spaces, tabs, newlines). This option allows to overcome silly limitations on the length of the command line.

Turning code into a library

To develop a library, it is usually more convenient to split it into several modules, that reflect the internal structure of the library. From the standpoint of the library users, however, it is preferable to view the library as a single module, with only one interface file (.zi file) and one implementation file (.zo file): linking is easier, and there is no need to put a bunch of #open directives, nor to have to remember the internal structure of the library.

The camllibr command allows having a single .zo file for the whole library. Here is how the Caml Light module system can be used (some say ``abused'') to have a single .zi file for the whole library. To be more concrete, assume that the library comprises three modules, windows, images and buttons. The idea is to add a fourth module, mylib, that re-exports the public parts of windows, images and buttons. The interface mylib.mli contains definitions for those types that are public (exported with their definitions), declarations for those types that are abstract (exported without their definitions), and declarations for the functions that can be called from the user's code:

(* File mylib.mli *)
type 'a option = None | Some of 'a;;    (* a public type *)
type window and image and button;;      (* three abstract types *)
value new_window : int -> int -> window (* the public functions *)
  and draw_image : image -> window -> int -> int -> unit
  and ...
The implementation of the mylib module simply equates the abstract types and the public functions to the corresponding types and functions in the modules windows, images and buttons:
(* File mylib.ml *)
type window == windows__win
 and image  == images__pixmap
 and button == buttons__t;;
let new_window = windows__open_window
and draw_image = images__draw
and ...
The files windows.ml, images.ml and buttons.ml can open the mylib module, to access the public types defined in the interface mylib.mli, such as the option type. Of course, these modules must not reference the abstract types nor the public functions, to avoid circularities.

Types such as windows__win in the example above can be exported by the windows module either abstractly or concretely (with their definition). Often, it is necessary to export them concretely, because the other modules in the library (images, buttons) need to build or destructure directly values of that type. Even if windows__win is exported concretely by the windows module, that type will remain abstract to the library user, since it is abstracted by the public interface mylib.

The actual building of the library mylib proceeds as follows:

camlc -c mylib.mli              # create mylib.zi
camlc -c windows.mli windows.ml images.mli images.ml
camlc -c buttons.mli buttons.ml
camlc -c mylib.ml               # create mylib.zo
mv mylib.zo tmplib.zo           # renaming to avoid overwriting mylib.zo
camllibr -o mylib.zo windows.zo images.zo buttons.zo tmplib.zo
Then, copy mylib.zi and mylib.zo to a place accessible to the library users. The other .zi and .zo files need not be copied.