Reusability is one of the keywords in software engineering today. It simply means to have source code that can be shared by several programs. Usually, modules are combined to libraries, and the library archive files can be linked into programs. As the idea might be simple, its practical implementation is complex because sharing of source code has an impact on all steps and phases in software production. This document only addresses the following administrative problems:
Storing the libraries in file hierarchies
Compiling and linking programs using such libraries
Managing dependencies between libraries
Objective Caml has a variety of language means to support reusability. Most important, polymorphic functions can be written which generalize the types of input arguments and the type of the result value. There are many examples in the core library such that I assume that the reader is familiar with this feature. Second, modules and functors must be mentioned which not only generalize types of values, but can even generalize structures, i.e. types with associated operations. Third, the class construct allows us to adopt the object-oriented techniques of abstraction such as inheritage and dynamic method lookup.
In the following, we are only analyzing the problem of making and using libraries from a purely software-technical point of view. This means, we ignore how to make functions polymorphic, and how to create functors and classes. Instead, we only look at how to invoke the O'Caml compiler to create, manage, and use libraries. Especially, we are interested in the administration of systems of libraries that have dependencies.
One of the complex operations on such a system is the replacement of a library by a newer version. Because of the strict compatibility checks of O'Caml, it is usually necessary to rebuild and reinstall all dependent libraries as well. With the help of findlib, one can find out which are the dependent libraries. (However, findlib does not provide a framework to rebuild them. For example, the GODI system includes such a framework.)
The library is also called a "package" when it is seen as a removeable and replaceable set of files. Findlib requires that there is a certain directory structure; it is not possible to install the files at arbitrary places (findlib does not even maintain a file list). For simplicity, every library is usually stored into its own directory, i.e. the library archive files and the interface files.
From the perspective of the compiler, the library is made accessible by adding the package directory to the search path of the compiler. By doing so, the modules of the library are added to the namespace universe, and thus can be opened by modules using them. This means that the approach "one package = one directory" can be naturally translated into language operations modifying the namespace scope.
When linking a program, it must be specified which link operation is necessary to use a certain library. Often, only a single archive file needs to be linked in, but sometimes additional archives or system libraries must be linked, too. Furthermore, the link operations often depends on certain conditions, e.g. whether a single- or multi-threaded program is being created.
The findlib library is my suggestion for a package manager suitable for Objective Caml. It is a library (stored as a package itself) which can answer the following questions:
If I want to use a package, which is the directory containing the compiled interfaces and implementations? - The package directory may vary from system to system, and this feature makes it easier to write Makefiles that run everywhere. Furthermore, OCaml can load modules dynamically, and it is not a good practice to compile in the location of such modules. The better way is to ask findlib where the module resides today.
Which other packages must be linked in, too, if I want to use a certain package?
Which archives need to be linked in, and which compiler options are necessary?
If there is a version of the archive with additional properties, which file should I use? - Additional properties are at least: Thread-safety, using POSIX threads, and being gprof-enabled. It is simple to add more criterions.
Furthermore, there is a frontend for this library called ocamlfind. It is a command-line interface for the library, but has also some additional abilities:
It can invoke ocamlc, ocamlopt, ocamlmktop, and ocamlcp such that compiler arguments necessary to use a package or link it in are automatically added.
It can install and uninstall packages.
It can find out dependent packages.
As you'll see in the following chapters, the usage of this library is really simple. If you want only to link in packages written by other people, you must only change the command that invokes the compiler, e.g. instead of calling "ocamlc program.ml" invoke "ocamlfind ocamlc -package name_of_package_to_use -linkpkg program.ml", and you can refer to the named package within program.ml. If you want to turn your collection of modules into a package, you need only to write one adminstrative file (META) containing all extra information such as required other packages.