Author: Christian.Queinnec@lip6.fr

## Modes de compilation

La distribution d'un langage dépend du processeur et du système d'exploitation. Pour chaque architecture (couple processeur, système d'exploitation), une distribution d'Objective CAML contient la boucle d'interaction, le compilateur de code-octet et dans la plupart des cas le compilateur natif sur cette architecture.

### Noms des commandes

La figure 7.5 donne les noms des commandes des différents compilateurs que l'on rencontre dans les distributions d'Objective CAML. Les quatre premières commandes sont disponibles pour toute distribution.

> `ocaml` | boucle d'interaction
> `ocamlrun` | interprète de code-octet
> `ocamlc` | compilateur en ligne de code-octet
> `ocamlopt` | compilateur en ligne de code natif
> `ocamlc.opt` | compilateur en ligne optimisé de code-octet
> `ocamlopt.opt` | compilateur en ligne optimisé de code natif
> `ocamlmktop` | constructeur de nouvelles boucles d'interaction

> Figure 7.5 : Commandes de compilation

Les compilateurs optimisés ont été eux-mêmes compilés avec le compilateur natif, produisant un exécutable plus rapide.

### Unité de compilation

L'unité de compilation correspond à la plus petite décomposition d'un programme Objective CAML pouvant être compilée. Pour la boucle d'interaction, l'unité de compilation correspond à une phrase du langage. Par contre pour les compilateurs en ligne, l'unité de compilation est un couple de fichiers : le fichier source et le fichier interface. Le fichier interface est optionnel. S'il n'existe pas, alors toutes les déclarations globales du fichier source seront visibles par une autre unité de compilation. La construction des fichiers d'interface sera décrite dans le chapitre sur la programmation modulaire (14). La liaison entre ces deux fichiers utilise les conventions de nommage des extensions de fichiers.

### Nommage des extensions de fichiers

La figure 7.6 présente les extensions des différents fichiers utilisés pour les programmes Objective CAML et C.

> extension | signification
> `.ml` | fichier source
> `.mli` | fichier interface
> `.cmo` | fichier objet (code-octet)
> `.cma` | fichier d'une bibliothèque objet (code-octet)
> `.cmi` | fichier interface compilé
> `.cmx` | fichier objet (natif)
> `.cmxa` | fichier d'une bibliothèque objet (natif)
> `.c` | fichier source C
> `.o` | fichier objet C (natif)
> `.a` | fichier d'une bibliothèque objet C (natif)

> Figure 7.6 : Extension des fichiers

Les fichiers `exemple.ml` et `exemple.mli` forment une unité de compilation. Le fichier d'interface compilé (`exemple.cmi`) est commun au compilateur de code-octet et au compilateur natif. Les fichiers provenant du monde C sont utilisés pour l'interfaçage de Objective CAML avec des bibliothèques C (12).

### Compilateur de code-octet

La forme générale de la commande d'un compilateur en ligne est la suivante :
Objective CAML suit la même règle. On tapera, par exemple :

    ocamlc -c exemple.ml

Les options passées au compilateur sur la ligne de commande suivent les conventions du système Unix. Elles sont précédées du caractère `-`. Les extensions des fichiers sont interprétées de la manière décrite à la figure 7.6. Dans l'exemple ci-dessus, le fichier `exemple.ml` est considéré comme un fichier source Objective CAML et sera donc compilé, ce qui produira les fichiers `exemple.cmo` et `exemple.cmi` car l'option `-c` indique au compilateur de n'engendrer que le code objet. Sans cette option, le compilateur `ocamlc` produit aussi un fichier exécutable `a.out`, c'est-à- dire qu'il effectue aussi l'édition de liens.
Le tableau de la figure 7.7 décrit les principales options du compilateur de code-octet. Le tableau de la figure 7.8 indique les autres options possibles.

> Principales options
> `-a` | construit une bibliothèque
> `-c` | compile sans faire l'édition de liens
> `-o` nom_executable | spécifie le nom de l'exécutable
> `-linkall` | indique de lier avec toutes les bibliothèques utilisées
> `-i` | affiche toutes les déclaration globales compilées
> `-pp` commande | utilise commande comme pré-processeur
> `-unsafe` | bascule en mode sans vérification des indices
> `-v` | affiche la version du compilateur
> `-w` liste | choisit selon liste le niveau des messages d'avertissement (voir fig. 7.9)
> `-impl` fichier | indique que fichier est un source Caml (.ml)
> `-intf` fichier | indique que fichier est une interface Caml (.mli)
> `-I` catalogue | ajoute catalogue dans la liste des catalogues

> Figure 7.7 : Principales options du compilateur de code-octet

> Autres options
> processus légers | `-thread` (19, page ??)
> mise au point | `-g`, `-noassert` (10, page ??)
> exécutables autonomes | `-custom`, `-cclib`, `-ccopt`, `-cc` (voir page ??)
> runtime | `-make-runtime` , `-use-runtime`
> interface C | `-output-obj` (12, page ??)

> Figure 7.8 : Autres options du compilateur de code-octet

Pour obtenir l'affichage de l'ensemble des options du compilateur de code-octet, il suffit de lui passer l'option `-help`.
Les niveaux de message d'avertissement (warning) sont décrits à la figure 7.9. Un niveau de message est une bascule (activée/désactivée) représentée par une lettre. Une majuscule active ce niveau et une minuscule le désactive.

> Principaux niveaux |
> `A/a` | active/désactive tous les messages
> `F/f` | application partielle dans une séquence
> `P/p` | pour les filtrages incomplets
> `U/u` | pour les cas inutiles d'un filtrage
> `X/x` | active/désactive tous les autres messages
> pour la couche objet | `M/m` et `V/v` (voir chapitre 15)

> Figure 7.9 : Description des avertissements de compilation

Par défaut le niveau maximal (`A`) est choisi par le compilateur.
Un exemple d'utilisation du compilateur de code-octet est donné figure 7.10.

> Figure 7.10 : Session avec le compilateur de code-octet

### Compilateur natif

Le compilateur natif possède un comportement proche de celui du compilateur de code-octet bien que les fichiers produits soient différents. Les options de compilation sont globalement les mêmes que celles décrites aux figures 7.7 et 7.8. Il faut cependant retirer les options liées au runtime de la figure 7.8. Les options spécifiques au compilateur natif sont données à la figure 7.11. Les différents niveaux de warning sont les mêmes.

> `-compact` | optimise en espace le code produit
> `-S` | conserve le code assembleur dans un fichier
> `-inline` niveau | indique le grain de traduction d'une fonction à plat

> Figure 7.11 : Options particulières pour le compilateur natif.

L'expansion en ligne (inlining) est une version élaborée de la macro-expansion du prétraitement. Elle remplace l'appel d'une fonction par le corps de la fonction où les arguments sont fixés. Plusieurs appels différents correspondront à une nouvelle traduction du corps de la fonction. On évite ainsi d'exécuter la séquence d'appel de fonction, mais la taille du code peut s'en trouver accrue. Les principaux niveaux d'inlining sont :

- 0 : l'expansion n'est autorisée que lorsqu'elle n'accroît pas la taille du code ;
- 1 : c'est la valeur par défaut, elle accepte une légère augmentation de la taille du code ;
- n > 1 : augmente la tolérance d'accroissement de la taille du code expansé.

### Boucle d'interaction

La boucle d'interaction ne possède que deux options pour son lancement :

- `-I` catalogue : qui ajoute le chemin indiqué en tête de la liste des chemins de recherche des fichiers sources ou compilés ;
- `-unsafe` : qui indique au compilateur de ne plus tester les débordements d'indice de tableaux ou de chaînes de caractères.

La boucle d'interaction possède plusieurs directives de compilation qui permettent de modifier interactivement son comportement. Elles sont décrites à la figure 7.12. Toutes les directives commencent par le caractère `#` et se terminent par les habituels `;;`.

> `#``quit``;;` | sort de la boucle d'interaction
> `#``directory` catalogue `;;` | ajoute un chemin en tête
> `#``cd` catalogue `;;` | change de catalogue courant
> `#``load` fichier_objet `;;` | charge un fichier `.cmo`
> `#``use` fichier_source `;;` | compile et charge un fichier source
> `#``print_depth` profondeur `;;` | modifie la profondeur d'affichage
> `#``print_length` largeur `;;` | idem pour la largeur
> `#``install_printer` fonction `;;` | spécifie une fonction d'affichage
> `#``remove_printer` fonction `;;` | repasse à l'afficheur standard
> `#``trace` fonction `;;` | trace les arguments d'une fonction
> `#``untrace` fonction `;;` | enlève la trace d'une fonction
> `#``untrace_all` `;;` | enlève toutes les traces

> Figure 7.12 : Directives de la boucle d'interaction

Les directives sur les catalogues respectent les conventions du système d'exploitation utilisé.
Les directives de chargement n'ont pas exactement le même comportement. La directive `#use` lit le fichier source indiqué comme s'il avait été tapé directement en interactif. La directive `#load` charge le fichier d'extension `.cmo` indiqué. Dans ce dernier cas, les déclarations globales de ce fichier ne sont pas directement accessibles.
Pour cela il faut utiliser la notation pointée. Si le fichier `exemple.ml` contient la déclaration globale `f`, alors une fois chargé le code-octet (`#load "exemple.cmo";;`), on accédera à la valeur de `f` par `Exemple.f`, où la première lettre du fichier est remplacée par une majuscule. Cette notation vient du système de modules d'Objective CAML (voir chapitre 14, page ??).
Les directives de paramétrage de la profondeur et de la largeur d'affichage permettent de contrôler l'affichage des valeurs. Ce qui est utile quand des valeurs volumineuses doivent être affichées.
Les directives de redéfinition des fonctions d'impression pour des types donnés permettent de définir leur présentation. Pour qu'elles s'intègrent bien avec l'affichage par défaut, il sera nécessaire d'utiliser la bibliothèque `Format` (8) pour les définir.
Les directives de traçage des arguments et du résultat de fonctions sont particulièrement utiles pour la mise au point des programmes. Elles seront manipulées au chapitre sur l'analyse de programme (10).
La figure 7.13 montre une session avec la boucle d'interaction.

> Figure 7.13 : Session avec la boucle d'interaction

### Construction de nouvelles boucles d'interaction

La commande `ocamlmktop` permet de construire de nouvelles boucles d'interaction dans lesquelles un certain nombre de bibliothèques ou modules sont préchargés. Outre le fait de ne plus avoir besoin d'effectuer les `#load` en début de session, cela est indispensable pour intégrer des bibliothèques écrites en C car il est alors nécessaire de modifier la bibliothèque d'exécution.
Les options de cette commande sont un sous-ensemble des options du compilateur de code-octet (`ocamlc`) :

`-cclib` libname, `-ccopt` option, `-custom`, `-I` catalogue et `-o` nom_executable

Le chapitre sur la programmation graphique (5, page ??) utilise cette commande pour construire un toplevel contenant la bibliothèque `Graphics` de la manière suivante :

    ocamlmktop -custom -o mytoplevel graphics.cma -cclib \
               -L/usr/X11/lib -cclib -lX11

Cette commande construit l'exécutable de nom `mytoplevel`, contenant la bibliothèque de code-octet `graphics.cma`. Cet exécutable autonome (`-custom` (voir section suivante) sera lié à la bibliothèque `X11` (`libX11.a`) qui elle-même sera recherchée dans le chemin `/usr/X11/lib`.