Chapitre 5 Environnement de développement C++
5.1 Compilation
5.1.1 Compilation d'une classe C++
Le compilateur traduit le code C++ en code objet (ou code
``machine''). Pendant ce cours, nous utiliserons le compilateur Gnu
C++, appelé g++. Ce compilateur a beaucoup d'options, et nous vous
incitons à vous reporter aux pages de manuel pour plus d'information.
Toutefois, voici les options les plus utiles :
-
-c
- --- Compiler les fichiers sources, mais sans
édition de liens. Le compilateur produit un fichier objet
.o pour chaque fichier source.
- -o fichRes
- --- Donner le nom fichRes au
fichier exécutable produit par la compilation et l'édition de liens. Quand
cette option n'est pas employée, le nom d'exécutable par défaut est
a.out.
- -g
- --- engendrer de l'information pour le débogage, à
utiliser avec un débogueur comme gdb (ou son interface
utilisateur ddd).
Pour compiler une classe C++ Toto (que nous supposerons
correcte), la commande à lancer est :
g++ -c Toto.cpp
Si la compilation s'achève sans erreur, vous récupérez dans votre
répertoire un fichier objet appelé Toto.o.
5.1.2 Compilation d'un programme C++
Un programme C++ est un fichier qui
-
inclut les headers de toutes les classes et
bibliothèques employées,
- comporte une fonction main : int main()
...corps du programme....
Pour compiler un programme C++, appelons-le monprog.cpp,
voici la marche à suivre :
g++ monprog.cpp C_1.o C_2.o ... C_n.o -o monprog
où C_1.o C_2.o ... C_n.o sont les fichiers objets des
classes compilées au préalable, et utilisées par le programme
monprog.cpp. L'option -o indique que le fichier
produit par la compilation doit s'appeler monprog.
C'est un exécutable pour l'architecture et le système sur
lesquels vous avez compilé1
le programme.
Le compilateur a besoin du nom des fichiers objets pour les passer à
l'édition de liens, qui ``assemble'' les différents morceaux
compilés pour en faire un fichier exécutable unique.
5.1.3 Construire des bibliothèques
Si vous créez un certain nombre de classes, vous ressentirez
rapidement le besoin de réunir les versions compilées de ces classes
dans une bibliothèque.
En Unix ou Linux, pour réunir des fichiers objets, on utilisera
typiquement la commande ar, qui permet de créer des fichiers
``archives'' :
ar r mabib.a C_1.o C_2.o ... C_n.o
L'option r indique qu'il faut remplacer les versions
existantes éventuelles des fichiers C_i.o par les nouvelles
versions fournies ; s'il n'y a pas de version existante, le fichier
est ajouté à l'archive.
Pour faire d'un fichier archive une bibliothèque utilisable, il faut
construire un index de toutes les fonctions et variables définies par
les différents fichiers objets qu'elle contient.
Ceci est fait par la commande ranlib, qu'on appelle souvent
systématiquement après ar :
ranlib mabib.a
La figure suivante résume les différentes étapes que nous avons
décrites :
monprog.cpp @>g++>> monprog @<Edition
de liens<<
mabib.a @<ar<ranlib<
|
{ |
C_1.o @<g++<< C_1.cppC_2.o @<g++<< C_2.cpp...C_n.o @<g++<< C_n.cpp |
|
|
5.2 Le préprocesseur
Les fichiers headers sont ajoutés au programme à compiler par
les instructions d'inclusion du préprocesseur.
Le préprocesseur traite le fichier source avant la compilation
proprement dite.
Il effectue surtout des remplacements lexicographiques sur le texte à
compiler.
Les instructions du préprocesseur commencent toutes par le caractère
#
; nous présentons ci-après les plus utiles d'entre elles.
5.2.1 L'instruction #include
L'instruction #include a la syntaxe suivante :
#include <some_lib>
#include "my_file.hh"
La première ligne indique qu'on inclut some_lib, qui est
le fichier header d'une bibliothèque, et qu'on trouvera dans un
chemin appartenant à une liste connue2.
La seconde ligne indique l'inclusion d'un fichier header fourni
par l'utilisateur, avec un chemin relatif à l'emplacement du fichier
source qui contient l'instruction d'inclusion.
Prenons comme exemple que nous voulons construire une classe
ManuscritAncien, définie par un fichier
ManuscritAncien.hh contenant l'interface de la classe, et un
fichier ManuscritAncien.cpp contenant la mise en oeuvre de
la classe. Le fichier ManuscritAncien.hh pourrait être de la
forme :
#include "Ouvrage.hh"
#include "Livre.hh"
class ManuscritAncien : public Livre {
...
corps de ManuscritAncien.hh
...
};
et le fichier ManuscritAncien.cpp :
#include <iostream>
#include "ManuscritAncien.hh"
....
body of ManuscritAncien.cpp
....
S'il manque l'inclusion (éventuellement en cascade) des interfaces de
toutes les bibliothèques et classes utilisées, la compilation
échouera...
NB : il faut minimiser les dépendances entre modules en n'incluant
que les directives #include strictement nécessaires à la
compilation d'un module donné.
5.2.2 Inclusion conditionnelle
L'instruction #if(n)def-define-endif sert (entre autres) à
éviter les inclusions multiples du même fichier :
#ifndef __POLYCOPIE_HH_INCLUDED__
#define __POLYCOPIE_HH_INCLUDED__
// définition de Polycopie.hh
#endif /* __POLYCOPIE_HH_INCLUDED__ */
teste si __POLYCOPIE_HH_INCLUDED__
a déjà été défini
C'est une constante du préprocesseur (à écrire en majuscules).
Si __POLYCOPIE_HH_INCLUDED__
n'a pas encore été défini,
// définition de Polycopie.hh est inclus et traité, sinon
il n'est pas inclus.
Nous ajoutons
#define __POLYCOPIE_HH_INCLUDED__
juste après l'instruction
#ifndef
pour garantir que la constante
__POLYCOPIE_HH_INCLUDED__
sera définie la première fois que le
fichier header est mentionné dans une directive d'inclusion.
La directive #ifdef
est souvent utilisée pour faire de la
compilation conditionnelle de morceaux de code, par exemple à des fins
de débogage :
int main () {
#ifdef DEBUG
cout << "begin of main()"<< endl;
#endif
....
// body of main()
....
#ifdef DEBUG
cout << "end of main()"<< endl;
#endif
}
5.3 Où trouver un compilateur C++ ?
Il existe un vaste choix de compilateurs C++ commerciaux.
Des solutions libres et gratuites existent également, quelques
pointeurs sont donnés ici :
-
Sous Windows :
-
Cygwin (
http://www.cygwin.com/
).
Un environnement qui permet d'émuler Linux sous Windows, et donc en
particulier de disposer de l'excellent compilateur G++/Gcc.
-
Dev-C++
(
http://www.bloodshed.net/devcpp.html
).
C'est un système complet de développement C/C++,
tournant directement sous Windows directement.
Il comprend un éditeur multi-fichiers, un
compilateur, un gestionnaire de projet et un débogueur.
Le compilateur de base est Gcc.
Pour les amateurs d'Eclipse, il faut noter que le plug-in
Cdt offre un environnement de développement pour C++. Associé à
Cygwin ou à MinGW3,
un environnement minimal Gnu sous Windows, pour accéder au
compilateur G++, il permet de travailler dans un cadre connu,
pour ceux qui ont pris l'habitude d'Eclipse pour développer en
Java.
-
Sous Linux : Gcc/G++.
Les sources sont téléchargeables à partir de
http://gcc.gnu.org/
, mais l'installation est
plus délicate.
Il est livré en standard avec certains systèmes Unix (comme Linux),
ce qui permet d'éviter l'étape d'installation.
Les débogueurs du monde Unix livrés en standard ne sont généralement
pas très conviviaux, mais il est possible de récupérer un débogueur
graphique (Ddd) à l'adresse
http://www.gnu.org/software/ddd/
.
Les personnes travaillant sous Linux utiliseront généralement leur
éditeur de texte favori (comme Emacs ou XEmacs) pour compléter cet
environnement.
Il existe cependant différents environnements de développement intégré
libres sous Linux, comme KDevelop, dont l'adresse d'accueil est
http://www.kdevelop.org/
.
- 1
- Le compilateur C++ produisant directement du code machine, et non du
bytecode comme en Java, un programme compilé sous un système
et sur une architecture n'a aucune raison de s'exécuter sur d'autres
architectures et/ou systèmes !
- 2
- Grâce à l'option -I du compilateur, vous pouvez ajouter vos
propres chemins aux chemins prédéfinis.
- 3
- http://sourceforge.net/projects/mingw/.