Invocation du compilateur via un script shell
Idée de stocker la commande de compilation
Nous avons vu qu'il était en général utile de spécifier de nombreuses options de débogage ou d'optimisation, ainsi que des options qui référencent des bibliothèques. Comment alors ne pas retaper une très longue commande à chaque fois que nous avons besoin de recompiler notre programme ? Utiliser le rappel de commande dans le terminal ? Insuffisant d'une session à l'autre. Pénible de chercher dans l'historique des commandes.
Il faut donc d'une manière ou d'une autre stocker la commande de compilation. L'idée la plus simple qui vient à l'esprit est de stocker la commande telle quelle. Où ? En commentaire dans le fichier source ?
- Pas pratique : copier-coller nécessaire à chaque session.
- Pas logique : information spécifique à un compilateur et une machine avec le code source Fortran indépendant du compilateur.
Déjà mieux que dans le fichier source : idée de stocker la commande de compilation dans un fichier à part, c'est-à-dire un script shell.
Manipulation 2
- Créer un fichier contenant la commande de compilation du programme trivial.
- Ajouter les options de débogage.
- Se servir de ce fichier pour compiler.
Programme à plusieurs fichiers
Il est intéressant de répartir le code d'un programme sur plusieurs fichiers pour : la clarté ; la gestion de versions ; le travail à plusieurs ; diminuer le temps de compilation (cf. infra).
L'idée simple de stocker la commande de compilation telle quelle se heurte à la difficulté engendrée par les programmes à plusieurs fichiers. Nous allons voir pourquoi. Mais expliquons d'abord comment compiler un programme à plusieurs fichiers.
Possibilité de compiler d'un coup tous les fichiers composant un programme :
gfortran [options] foo1.f90 foo2.f90 ...
mais ce n'est pas conseillé (cf. infra).
Décomposition de la compilation
Au lieu de compiler d'un coup tous les fichiers composant un programme comme ci-dessus, il est aussi possible de décomposer la compilation en plusieurs commandes :
gfortran [options de compilation] -c foo1.f90
gfortran [options de compilation] -c foo2.f90
gfortran [options d'édition de liens] foo1.o foo2.o
Il y a \(n\) commandes pour la compilation de \(n\) fichiers, plus une commande finale, dite "d'édition de liens". Cette décomposition ouvre la perspective de ne recompiler que le nécessaire et donc de gagner en temps de compilation. Examinons de plus près les commandes qui décomposent la compilation :
- La compilation d'un fichier source seul, qui est une partie
seulement d'un programme, produit un "fichier objet", en langage
machine, non exécutable, suffixe
.o
. - La création du fichier exécutable à partir des fichiers objets et des bibliothèques s'appelle l'édition de liens.
-
Les fichiers
.o
sont des intermédiaires produits par la compilation. Ils ne sont pas utiles à l'exécution du programme. -
L'option supplémentaire
-c
(la même pour tous les compilateurs) est requise pour la compilation d'un fichier qui est une partie seulement d'un programme (sans édition de liens).
L'idée pour réduire le temps de compilation, après modification d'un fichier source, est donc de ne re-compiler que ce fichier et refaire l'édition de liens.
Ordre de compilation
L'utilisation de modules en Fortran implique un ordre de compilation. Ordre entre les fichiers s'il y a plusieurs fichiers, ou ordre d'écriture des modules à l'intérieur d'un fichier.
S'il y a :
use bar_m
dans la procédure foo
alors le module bar_m
doit être compilé avant
la procédure foo
(avant le module contenant la procédure
foo
). Donc :
- Si
bar_m
etfoo
sont dans le même fichier alorsbar_m
doit être avantfoo
dans ce fichier. - Sinon le fichier contenant
bar_m
doit être compilé d'abord.
Fichier .mod
La compilation d'un fichier contenant un module crée un fichier .mod
.
-
bar_m.mod
si le module s'appellebar_m
(le nom du fichier.mod
est formé à partir du nom du module et non à partir du nom du fichier.f90
) -
bar_m.mod
contient (sous forme lisible seulement par le compilateur) les informations sur l'interface du module, y compris l'interface des procédures publiques du module (function
ousubroutine
, type des arguments, scalaires ou tableaux,intent
, etc.).
S'il y a :
use bar_m
dans la procédure foo
alors :
gfortran [options de compilation] -c foo.f90
a besoin de bar_m.mod
. D'où la contrainte d'ordre de compilation.
Les fichiers .mod
sont, comme les fichiers .o
, des intermédiaires
produits par la compilation. Ils ne sont pas utiles à l'exécution du
programme.
Graphe de dépendances
En regardant les fichiers sources, on peut déduire une suite de dépendances. Imaginons par exemple :
foo1.f90 → foo2.f90, bar.f90
bar.f90 → foo2.f90, plouf1.f90
plouf.f90 → foo2.f90, foo1.f90
(la flèche signifie "doit être compilé après"). La liste de dépendances définit le graphe des dépendances (un graphe directionnel acyclique) :
Mais il reste une analyse à faire pour trouver l'ordre de compilation : choisir un parcours de ce graphe.
Nécessité d'un outil
Le simple listage des commandes de compilations telles quelles dans un fichier shell est donc insuffisant :
- il ne permet pas de recompiler uniquement le nécessaire ;
- il ne permet pas de trouver l'ordre de compilation.
Accessoirement : nous ne voulons pas répéter l'écriture des options de compilation :
gfortran [options de compilation] -c foo1.f90
gfortran [options de compilation] -c foo2.f90
donc nous voulons stocker les options de compilation dans une variable.
make
est l'outil historique qui permet de pallier à l'insuffisance
d'un fichier shell contenant les commandes de compilations.