© D. Mathieu
mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique
Créé le 04/08/2000 - Dernière mise à jour : 17/10/2001
option -o : choix du nom de l'exécutableConclusions
option -c : suppression de l'édition de liens
option -I : répertoire(s) des fichiers inclus
option -D : positionnement de macros
option -s : suppression d'informations pour le débogueur
option -W : messages "warning"
option -l : utilisation de bibliothèque(s)
option -L : répertoire(s) des bibliothèque(s)
Remarques préliminaires :
Ce document ne constitue pas un cours sur la commande Unix de compilation (C ou C++, quel que soit le compilateur, ici compilateur g++ : projet GNU Egcs-1.1.2 release). Il se contente de rappeler quelques éléments fondamentaux et indispensables à l'utilisation de ces compilateurs.
On pourra trouver dans le document "Tests effectués sur le compilateur g++" des remarques personnelles et des essais sur des bugs détectés dans cette version, des améliorations constatees par rapport à la version précédente, des points non conformes à la norme C++, etc...
g++ simple.cxx |
Elle s'exécute en plusieurs phases :
Lorsque le code est scindé dans plusieurs fichiers source, par exemple complexe.cxx, Part1.cxx et Part2.cxx, la production de l'exécutable peut être obtenue par :
g++ complexe.cxx Part1.cxx Part2.cxx |
quel que soit l'ordre des fichiers .cxx dans la commande. Cela n'a pas toujours été le cas et, pour éviter tout désagrément avec un ancien compilateur, il est préférable de les mettre dans l'ordre des dépendances, de même que pour l'édition des liens.
Après compilation, le répertoire courant contient le fichier exécutable a.out.
Les options présentées ici le sont par ordre chronologique : les premières sont immédiatement nécessaires, les dernières peuvent être ignorées dans un premier temps.
Sauf pour de petits essais, il est maladroit d'utiliser comme nom de commande l'identificateur par défaut a.out.
Au contraire, il est habituel (et conseillé) de donner à la commande le nom du fichier source qui contient la fonction main(), dépourvu d'extension (pour les TPs de système, c'est le nom du fichier qui contient la fonction ppal() qui doit être utilisé).
Ici, l'exécutable sera donc simple.
C'est l'option -o, suivie d'un espace et du nom d'exécutable choisi, qui permet d'obtenir ce résultat :
g++ simple.cxx -o simple |
La place de l'option dans la ligne est indifférente
:
g++ -o simple simple.cxx |
g++ -o complexe complexe.cxx Part1.cxx Part2.cxx |
Il est peu efficace de recompiler la totalité
des fichiers sources lorsqu'un seul a été modifié.
Il faut alors faire de la compilation séparée, et
dissocier les deux dernières phases : compilation et édition
de liens. Pour reprendre l'exemple ci-dessus, il faut compiler en trois
fois les fichiers sources complexe.cxx, Part1.cxx et
Part2.cxx, pour obtenir les fichiers objets .o correspondants,
puis faire l'édition de liens de ces derniers. L'arrêt de
la compilation après obtention du fichier objet (.o), est
réalisé grâce à l'option -c :
g++ -c complexe.cxx
g++ -c Part1.cxx g++ -c Part2.cxx |
l'édition de liens est obtenue par :
g++ -o complexe complexe.o Part1.o Part2.o |
Si par exemple le fichier Part1.cxx doit
être recompilé, la commande suivante peut alors être
utilisée :
g++ -o complexe complexe.o Part1.cxx Part2.o |
Remarque : l'option -c n'a de sens qu'utilisée dans la phase de compilation.
Le C/C++ distingue deux sortes de fichiers entête (fichiers inclus)
#include <iostream> // inclusion
d'un fichier C++
#include <unistd.h> // inclusion d'un fichier C pour la fonction open() par exemple #include <sys/types.h> // inclusion d'un fichier C pour le type size_t par exemple |
La présence des caractères <> indique au compilateur qu'il doit aller chercher ces fichiers conventionnellement dans un répertoire déterminé lors de la configuration.
Généralement, les <> représentent le chemin /usr/include pour le C et /usr/include/g++-2 pour le C++, et, comme le montre la troisième ligne, des sous-répertoires peuvent être indiqués explicitement.
#include "fonctions.h"
// inclusion à partir du répertoire courant
#include "../../tpC++/tp10/nsBAO.h" // chemin relatif au répertoire courant #include "/users/prof/mathieu/entete.h" // chemin absolu |
L'utilisation des chemins, absolus ou relatifs, permet d'inclure des
fichiers standard au moyen des "", mais cela reste fortement
déconseillé :
#include "/usr/include/unistd.h" |
Supposons que les fichiers locaux.h, nsSysteme.h et nsNet.h soient respectivement (à partir du noeud /users/etud2/taralf/tp/), dans les répertoires tpsys/dirfile, tpsys/include et tpnet/include.
En utilisant la commande suivante :
g++ -o complexe.cxx -I/users/etud2/taralf/tp/tpsys/dirfile \
-I/users/etud2/taralf/tp/tpsys/include \ -I/users/etud2/taralf/tp/tpnet/include |
avec :
// fichier complexe.cxx
// #include "locaux.h" #include "nsSysteme.h" #include "nsNet.h" // ... |
le compilateur va chercher chacun des trois fichiers inclus successivement :
Remarques :
Og++ -o complexe.cxx -I$(HOME)/tp/tpsys/dirfile \
-I$(HOME)/tp/tpsys/include \ -I$(HOME)/tp/tpnet/include |
Les macros destinées au préprocesseur
sont très souvent utilisées pour effectuer de la compilation
conditionnelle. Ainsi, la séquence suivante n'est compilée
que si le préprocesseur a rencontré dans la même
phase de compilation, la définition de la macro _DEBUG
:
// fichier complexe.cxx
// ... #define _DEBUG ... #ifdef _DEBUG #include "nsSystemeDbg.hxx" // contient les mêmes fonctions que nsSysteme.hxx, // avec des informations de débogage en plus #else #include "nsSysteme.hxx" #endif |
Dans l'exemple suivant :
// fichier Part1.cxx
// ... #define _DEBUG ... |
// fichier complexe.cxx
// ... #ifdef _DEBUG #include "nsSystemeDbg.hxx" // contient les mêmes fonctions que nsSysteme.hxx, // avec des informations de débogage en plus #else #include "nsSysteme.hxx" #endif |
la macro _DEBUG n'est pas déclarée
lorsque le compilateur compile le fichier complexe.cxx par la
commande :
g++ -o complexe Part1.cxx Part2.cxx complexe.cxx |
car il s'agit d'unités de compilation différentes : elles donnent lieu à trois fichiers objets.
Les macros peuvent être définies au
lancement de la commande g++, grâce à l'option -D
suivie (sans espace) de la macro définie (autant d'options
-D que de macros à définir). Par exemple :
g++ -c -D_DEBUG complexe.cxx |
Remarques :
g++ -c complexe.cxx -Wall |
Nous vous conseillons vivement de ne pas supprimer cette option, même si les messages sont parfois nombreux et peuvent être négligés : ils font souvent apparaître des petites erreurs qui peuvent avoir de grandes conséquences ...
Remarque : il est absurde d'utiliser cette option pour la phase d'édition de liens !
Outre les bibliothèques standard qu'il est inutile de signaler (libc.a par exemple, qui est la bibliothèque standard du C), plusieurs bibliothèques peuvent être utilisées, comme par exemple libgcc.a, libg++.a. Il est aussi possible d'ajouter à la ligne de compilation (pour l'édition de liens) la liste des bibliothèques personnelles.
L'identificateur d'une bibliothèque doit commencer par lib et avoir pour extension .a.
Ces deux parties ne sont jamais indiquées dans la ligne de commande.
Une bibliothèque peut être créée et gérée par la commande
ar.
Par exemple, s'il existe deux bibliothèques libSys.a et libNet.a, elles peuvent être utilisées dans la ligne de compilation de la façon suivante :
g++ -s -o exo_01 exo_01.o -lSys -lNet |
L'option -L peut être utilisée pour indiquer le(s) répertoire(s) dans le(s)quel(s) le compilateur doit aller chercher les bibliothèques utilisées, par exemple :
g++ -s -o exo_01 exo_01.o -L$(HOME)/tp/tpsys -lSys -L$(HOME)/tp/tpnet -lNet |
Les commandes de compilation étant longues et répétitives, nous vous engageons à utiliser les possibilités des alias, et surtout de la commande make.
© D. Mathieu
mathieu@romarin.univ-aix.fr
I.U.T.d'Aix en Provence - Département Informatique