Next: Bibliothèques
Up: Quelques éléments de Caml
Previous: Structures de données polymorphes
On dispose d'un système de modules simple qui définit un module comme un couple de fichiers. Le fichier d'interface spécifie les fonctionalités offertes par le module, et le fichier d'implémentation contient le code source qui crée ces fonctionalités. Le fichier d'interface a l'extension .mli (ml interface) et le fichier d'implémentation l'extension .ml. Prenons l'exemple d'un module stack implémentant les piles. Son fichier d'interface est le fichier stack.mli suivant:
(* Stacks *) (* This module implements stacks (LIFOs), with in-place modification. *) type 'a t;; (* The type of stacks containing elements of type ['a]. *) exception Empty;; (* Raised when [pop] is applied to an empty stack. *) value new: unit -> 'a t (* Return a new stack, initially empty. *) and push: 'a -> 'a t -> unit (* [push x s] adds the element [x] at the top of stack [s]. *) and pop: 'a t -> 'a (* [pop s] removes and returns the topmost element in stack [s], or raises [Empty] if the stack is empty. *) and clear : 'a t -> unit (* Discard all elements from a stack. *) and length: 'a t -> int (* Return the number of elements in a stack. *) and iter: ('a -> 'b) -> 'a t -> unit (* [iter f s] applies [f] in turn to all elements of [s], from the element at the top of the stack to the element at the bottom of the stack. The stack itself is unchanged. *) ;;L'interface déclare les signatures des objets fournis par le module, types, exceptions ou valeurs. Une implémentation répondant à cette spécification est:
type 'a t = { mutable c : 'a list };; let new () = { c = [] };; let clear s = s.c <- [];; let push x s = s.c <- x :: s.c;; let pop s = match s.c with | hd::tl -> s.c <- tl; hd | [] -> raise Empty;; let length s = list_length s.c;; let iter f s = do_list f s.c;;
La compilation de l'interface du module stack produit un fichier stack.zi et celle de l'implémentation le fichier stack.zo. Quand le module stack est compilé, on dispose de ses fonctionalités en écrivant la ligne
#open "stack";;
en tête du fichier qui l'utilise. L'appel direct des identificateurs fournis par le module utilise la notation qualifiée, qui consiste à suffixer le nom du module par le symbole __ suivi de l'identificateur. Ainsi stack__pop désigne la fonction pop du module stack. Nous avons déjà utilisé la notation dans nos programmes pour désigner les exceptions sys__Break et sys__Sys_error du module sys. De même, il est courant de ne pas ouvrir le module printf pour un simple appel à la fonction d'impression formatée: on appelle directement la fonction printf par son nom qualifié printf__printf.
Pour qu'on puisse accéder aux identificateurs du module stack, il faut que ce module soit accessible, c'est-à-dire résidant dans le répertoire de travail actuel ou bien dans la bibliothèque standard de Caml Light, ou bien encore dans l'un des répertoires indiqués sur la ligne de commande du compilateur avec l'option -I. Lors de la création de l'exécutable, il faut également demander l'édition des liens de tous les modules utilisés dans l'application (autres que les modules de la bibliothèque standard).
Les modules permettent évidemment la compilation séparée, ce qui sous le système Unix s'accompagne de l'utilisation de l'utilitaire make. Nous donnons donc un makefile minimum pour gérer un programme découpé en modules. On s'inspirera de ce fichier pour créer ses propres makefiles. Dans ce squelette de fichier make, la variable OBJS est la liste des modules, et EXEC contient le nom de l'exécutable à fabriquer. Pour simplifier, on suppose qu'il y a deux modules seulement module1 et module2, et que l'exécutable s'appelle prog.
CAMLC=camlc -W -g -I . OBJS= module1.zo module2.zo EXEC= prog all: $(OBJS) $(CAMLC) -o $(EXEC) $(OBJS) clean: rm -f *.z[io] *.zix *~ #*# depend: mv Makefile Makefile.bak (sed -n -e '1,/^### DO NOT DELETE THIS LINE/p' Makefile.bak; \ camldep *.mli *.ml) > Makefile rm Makefile.bak .SUFFIXES: .SUFFIXES: .ml .mli .zo .zi .mli.zi: $(CAMLC) -c $< .ml.zo: $(CAMLC) -c $< ### EVERYTHING THAT GOES BEYOND THIS COMMENT IS GENERATED ### DO NOT DELETE THIS LINE
La commande make all ou simplement make, refabrique
l'exécutable et make clean efface les fichiers compilés.
Les dépendances entre modules sont automatiquement recalculées en lançant
make depend. La commande camldep est un perl
script qui se trouve à l'adresse
http://pauillac.inria.fr/caml/FAQ/FAQ_EXPERT-fra.html#make.
1/11/1998