Les outils de compilation

Chapitres traités   

Dans cette étude, nous allons mettre en oeuvre tout ce que nous avons appris sur la gestion multi-fichiers à l'aide d'un compilateur qui fonctionne aussi bien sous Windows que sous Linux. Il s'agit du célèbre compilateur GCC, qui est lui-même la version libre du compilateur CC qui existe dans le monde d'UNIX. Nous retrouvons d'ailleurs les mêmes types de commandes.


GCC est le nom générique de la suite d'outils de développement basée sur le compilateur C/C++ GNU développé par la Free Software Foundation. Cette suite d'outils est très souple et peut être utilisé pour les différentes phases de production des binaires : preprocessing des fichiers sources, compilation, assemblage et édition de lien.

 

Choix du chapitre Principaux outils

Les outils disponibles dans GCC sont les suivants :

Outil Description
gcc Compilateur GNU du langage C.
g++ Compilateur GNU du langage C++.
c++ Alias de g++.
cpp Préprocesseur C.
cc1 Compilateur C.
cc1plus Compilateur C++.
gasp Préprocesseur pour l'assembleur.
as Assembleur.
ar Archiveur.
ld Éditeur de liens.
make Programme de gestion des dépendances pour la construction des projets.
gdb Débogueur symbolique.
strip Extracteur d'informations symboliques de déboguage.
gperf Profiler.
gcov Analyseur de taux de couverture.
g77 Traducteur de Fortran 77 en C.
dlltool Outil de génération des tables d'exportation et des librairies d'importation des DLLs pour Windows.
windres Compilateur de fichiers de ressources pour Windows.

Les commandes les plus utilisées sont gcc, g++ avec également, nous le découvrirons plus tard, la commande make. Ainsi gcc et g++ sont les commandes de base enchaînant automatiquement l'appel des différents outils réalisant la traduction d'un programme source en un binaire exécutable. les phases successives sont :

  1. La précompilation réalisé par le précompilateur ou préprocesseur cpp qui traite les directives telles que l'inclusion de fichiers, les compilations conditionnelles, etc.
  2. La compilation proprement dite qui traduit le programme source en langage d'assemblage correspondant au processeur utilisé par la machine hôte avec optimisation éventuelle. Suivant que nous travaillons en langage C ou en langage C++, GCC propose deux compilateurs différents : appel du compilateur C (nommé cc1), ou C++ (cc1plus) selon le type de fichier à compiler (les fichiers .c sont compilés en C, les fichiers .C, .cc et .cpp sont compilés en C++). Les compilateurs génèrent un fichier assembleur.
  3. L'assemblage qui traduit les fichiers assembleurs en code binaires (modules objets). L'utilitaire correspondant se nomme as.
  4. L'édition de lien : qui rassemble les différents fichiers binaires et extrait des bibliothèques les fonctions utilisées. L'édition de lien est réalisée par la commande ld.

g++ est l'utilitaire pour le langage C++, qui effectue le même travaille que gcc, mais qui ajoute également les librairies C++ à la ligne de commande de l'éditeur de liens. c++, s'il est présent, est le même programme que g++, fourni sous un autre nom.

Extension des fichiers

Les références des fichiers qu'utilise la commande g++ ou gcc ont des extensions particulières qui déterminent alors quelle est la phase du processus exécuté actuellement :

  1. L'extension .c : indique un fichier source en langage C à soumettre à toutes les phases.
  2. L'extension .C, .cc ou .cpp : indique également un fichier source, mais en langage C++.
  3. L'extension .i : indique que le fichier correspondant a été produit par le préprocesseur..
  4. L'extension .s : indique un fichier produit par le compilateur sans assemblage. A partir de ce fichier, l'assembleur peut ensuite prendre le relais.
  5. L'extension .o : caractérise un module objet auquel ne sera appliqué que la phase d'édition de liens ou qui sert également pour fabriquer une bibliothèque (archive).
  6. L'extension .a : caractérise une archive constituée au moyen de l'utilitaire ar.

 

Choix du chapitre Les utilitaires gcc et g++

gcc (ou g++) disposent des options classiques de la plupart des compilateurs. Les principales options sont définies ci-dessous :

Option Signification
—help Affiche l'aide de GCC.
—version Donne la version de GCC.
-E Appelle le préprocesseur. N'effectue pas la compilation.
-S Appelle le préprocesseur et effectue la compilation. N'effectue pas l'assemblage ni l'édition de lien. Seuls les fichiers assembleur (« .S ») sont générés.
-c Appelle le préprocesseur, effectue la compilation et l'assemblage, mais ne fait pas l'édition de lien. Seuls les fichiers objets (« .o ») sont générés.
-o nom Impose le nom du fichier exécutable généré lors de la compilation d'un fichier source.
-g Génère les informations symboliques de déboguage.
-fexceptions Active la gestion des exceptions C++.
-fpic Génère du code relogeable. Cette option est nécessaire pour la compilation des fichiers utilisés dans une DLL ou un fichier chargeable dynamiquement.
-On Indique le niveau d'optimisation (n peut prendre les valeurs allant de 0 à 3, ou « s » pour optimiser la taille des binaires).
-mcpu=cpu Indique le type de processeur pour lequel le code doit être optimisé. Le code fonctionnera sur tous les processeurs de la famille de ce processeur.
-march=cpu Indique le type de processeur pour lequel le code doit être généré. Le code généré sera spécifique à ce processeur, et ne fonctionnera peut-être pas sur un autre modèle de la même famille. Cette option active automatiquement l'option -mcpu avec le même processeur.
-pipe Utilise les pipes systèmes au lieu des fichiers temporaires pour les communications entre le préprocesseur, le compilateur et l'assembleur.
-w Supprime tous les warnings.
-W Active les warnings supplémentaires.
-Wall Active tous les warnings possibles.
-mwindows Crée un exécutable GUI Windows.
-mdll Crée une DLL Windows.
-fvtable-thunks Utilise le mécanisme des tables de fonctions virtuelles. Cette option est nécessaire pour utiliser les interfaces COM sous Windows.

La plupart des autres options ne sont pas gérées directement par gcc. Elles sont directement communiquées aux programmes appelés par lui. Les options de ces programmes peuvent donc souvent être utilisées avec gcc, voir la documentation de ces programmes pour plus de renseignements.

Il est également possible de passer des options spécifiques aux programmes appelés par gcc (ou g++) à l'aide de l'option -W<lettre>. Les options les plus utiles sont les suivantes :

Option Signification
-Wa,<options> Passe les options suivantes à l'assembleur. Les options doivent être séparées par des virgules.
-Wp,<options> Passe les options suivantes au préprocesseur. Les options doivent être séparées par des virgules.
-Wl,<options> Passe les options suivantes à l'éditeur de liens. Les options doivent être séparées par des virgules.

gcc (ou g++) prennent directement en ligne de commande les fichiers à traiter. L'ordre des fichiers n'a pas d'importance, sauf pour les fichiers de librairies. Les librairies doivent être passées à la fin, parce qu'elles ne sont utilisées que si l'éditeur de lien y trouve des symboles non résolus au moment de l'utilisation de la librairie.

 

Choix du chapitre Utilisation de gcc et g++

Nous allons maintenant mettre en pratique ces utilitaires afin de bien comprendre le rôle de ces différentes options suivant le cas souhaité. Pour cela, nous allons reprendre et adapter l'étude que nous avons vue dans le cours précédent.

Dans un premier temps, nous ne fabriquerons pas la bibliothèque Mathématique. Nous passerons systématiquement par les fichiers objets principal.o, impaire.o et paire.o (dans le cadre de GCC, les extensions des fichiers objets sont .o et non .obj).

Fichiers sources

 

mathematique.h
#ifndef MathematiqueH
#define MathematiqueH

bool impaire(int x);
bool paire(int x);

#endif
impaire.cc
bool impaire(int x) 
{ 
   return (x%2)!=0; 
}
paire.cc
#include "mathematique.h"

bool paire(int x) 
{ 
   return !impaire(x); 
}
principal.cc
#include <iostream>
using namespace std;
#include "mathematique.h"

int main() {
   bool valeur = paire(7);
   cout << "valeur = " << valeur << endl;
   return 0;
}

 

Service minimum - production d'un exécutable désigné - g++ (sans option)

Nous allons maintenant tester un certain nombre d'options qu'utilise cette commane g++ au travers d'exemples qui traduit le besoin du développeur. Tout d'abord, nous utilisons la commande g++ sans option. Dans ce cas là, g++ produit un fichier exécutable qui se nomme a.exe (dans le cas de Windows) ou a.out (dans le cas de Linux).

Vous devez juste fournir l'ensemble des fichiers sources qui sont nécessaires à l'aboutissement de cet exécutable à la suite de cette commande, chacun de ces fichiers étant séparé d'un espace du voisin. Ici cela sera :

g++ principal.cc impaire.cc paire.cc

Pour arriver à la construction de cet exécutable, je rappelle que g++ passe par toutes les phases de compilation, à savoir :

  1. La précompilation,
  2. La compilation proprement dite,
  3. L'assemblage,
  4. L'édition de lien.

Durant toutes ces phases, des fichiers temporaires sont créés et automatiquement détruits.
.

Voici donc ci-dessous un scénario qui part des fichiers sources pour aboutir à l'exécutable a.exe que nous utilisons immédiatement afin de tester le résultat :

C:\travail>ls -l     // lister l'ensemble des fichiers présent dans le répertoire
total 4
-rwxrwxrwx 1 Emmanuel REMY Aucun    47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun    93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun    81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun  174 Aug 28 08:03 principal.cc

C:\travail>g++ principal.cc impaire.cc paire.cc   // création de l'exécutable a.exe en suivant toutes les phases de compilation

C:\travail>ls -l
total 396
-rwxrwxrwx 1 Emmanuel REMY Aucun 477569 Aug 28 08:04 a.exe
-rwxrwxrwx 1 Emmanuel REMY Aucun         47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun         93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun         81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun       174 Aug 28 08:03 principal.cc

C:\travail>a   // lancement de l'exécutable a.exe
valeur = 0

C:\travail>

 

Comment se rappeler l'ensemble des options qui constitue la commande g++ - Demande d'aide - g++ --help

Vous ne vous souvenez plus des options de la commande g++, demandez de l'aide en utilisant l'option --help :

C:\travail>g++ --help
Usage: g++ [options] file...
Options:
  -pass-exit-codes         Exit with highest error code from a phase
  --help                   Display this information
  --target-help            Display target specific command line options
  (Use '-v --help' to display command line options of sub-processes)
  -dumpspecs               Display all of the built in spec strings
  -dumpversion             Display the version of the compiler
  -dumpmachine             Display the compiler's target processor
  -print-search-dirs       Display the directories in the compiler's search path

  -print-libgcc-file-name  Display the name of the compiler's companion library
  -print-file-name=<lib>   Display the full path to library <lib>
  -print-prog-name=<prog>  Display the full path to compiler component <prog>
  -print-multi-directory   Display the root directory for versions of libgcc
  -print-multi-lib         Display the mapping between command line options and
                           multiple library search directories
  -print-multi-os-directory Display the relative path to OS libraries
  -Wa,<options>            Pass comma-separated <options> on to the assembler
  -Wp,<options>            Pass comma-separated <options> on to the preprocessor

  -Wl,<options>            Pass comma-separated <options> on to the linker
  -Xassembler <arg>        Pass <arg> on to the assembler
  -Xpreprocessor <arg>     Pass <arg> on to the preprocessor
  -Xlinker <arg>           Pass <arg> on to the linker
  -save-temps              Do not delete intermediate files
  -pipe                    Use pipes rather than intermediate files
  -time                    Time the execution of each subprocess
  -specs=<file>            Override built-in specs with the contents of <file>
  -std=<standard>          Assume that the input sources are for <standard>
  -B <directory>           Add <directory> to the compiler's search paths
  -b <machine>             Run gcc for target <machine>, if installed
  -V <version>             Run gcc version number <version>, if installed
  -v                       Display the programs invoked by the compiler
  -###                     Like -v but options quoted and commands not executed
  -E                       Preprocess only; do not compile, assemble or link
  -S                       Compile only; do not assemble or link
  -c                       Compile and assemble, but do not link
  -o <file>                Place the output into <file>
  -x <language>            Specify the language of the following input files
                           Permissible languages include: c c++ assembler none
                           'none' means revert to the default behavior of
                           guessing the language based on the file's extension

Options starting with -g, -f, -m, -O, -W, or --param are automatically
 passed on to the various sub-processes invoked by g++.  In order to pass
 other options on to these processes the -W<letter> options must be used.

For bug reporting instructions, please see:
<URL:http://gcc.gnu.org/bugs.html>.

C:\travail>

 

Spécifier le nom de l'exécutable - g++ -o

Il est généralement préférable de désigner le fichier exécutable afin de le déployer sur l'ensemble des machines qui utiliseront ce logiciel. Sinon, tous les logiciels porteraient le même nom a.exe. Pour cela, il suffit de préciser le nom de l'exécutable juste à la suite de l'option -o de la commande g++. Cette option peut être placée n'importe où sur la ligne de commande :

g++ principal.cc impaire.cc paire.cc -o calcul
g++ -o calcul principal.cc impaire.cc paire.cc

Voici, un scénario montrant la compilation et l'utilisation du logiciel calcul :

C:\travail>ls -l
total 4
-rwxrwxrwx 1 Emmanuel REMY Aucun  47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun  93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun  81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun 174 Aug 28 08:03 principal.cc

C:\travail>g++ principal.cc impaire.cc paire.cc -o calcul

C:\travail>ls -l
total 476
-rwxrwxrwx 1 Emmanuel REMY Aucun 477569 Aug 29 09:33 calcul.exe
-rwxrwxrwx 1 Emmanuel REMY Aucun         47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun         93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun         81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun       174 Aug 28 08:03 principal.cc

C:\travail>calcul
valeur = 0

C:\travail>

Visualisation du résultat produit par le préprocesseur - g++ -E

L'option -E de la commande g++ appelle le préprocesseur sans effectuer de compilation. Aucun fichier n'est produit. Le résultat est directement visible à l'écran.

g++ -E paire.cc

Voici un scénario qui montre la phase du préprocesseur du source paire.cc où nous voyons bien l'inclusion du fichier en-tête "mathématique.h" :

C:\travail>g++ -E paire.cc
# 1 "paire.cc"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "paire.cc"
# 1 "mathematique.h" 1



bool impaire(int x);
bool paire(int x);
# 2 "paire.cc" 2

bool paire(int x)
{
   return !impaire(x);
}

C:\travail>

Visualisation de la compilation sans la phase d'assemblage ni l'édition de lien - g++ -S

Il est possible de vérifier la compilation d'un fichier suivant le type de processeur utilisé. En effet, je rappelle que la compilation consiste à faire une traduction entre un langage de programmation facilement compréhensible par le programmeur (comme le C++) vers le langage binaire (machine) qui lui sera compréhensible par la machine, plus précisément, par le µprocesseur qui effectue tout un tas de traitements élémentaires correspondant à des algorithmes sophistiqués issus des langages de hauts niveaux. Avant de passer directement au langage binaire, les compilateurs passent toujours par le langage assembleur correspondant au type de µprocesseur utilisé. Nous pouvons le visualiser au moyen de l'option -S. Dans ce cas là, l'utilitaire g++ produit un fichier du même nom portant l'extension ".s" :

g++ -S calcul impaire.cc
--> impaire.s

Voici un scénario qui permet de contrôler le fichier assembleur pour un processeur Intel du fichier source impaire.cc :

C:\travail>ls -l
total 4
-rwxrwxrwx 1 Emmanuel REMY Aucun  47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun  93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun  81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun 174 Aug 28 08:03 principal.cc

C:\travail>g++ -S impaire.cc

C:\travail>ls -l
total 5
-rwxrwxrwx 1 Emmanuel REMY Aucun  47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun 243 Aug 29 09:40 impaire.s
-rwxrwxrwx 1 Emmanuel REMY Aucun  93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun  81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun 174 Aug 28 08:03 principal.cc

C:\travail>cat impaire.s
        .file   "impaire.cc"
        .text
        .align 2
.globl __Z7impairei
        .def    __Z7impairei;   .scl    2;      .type   32;     .endef
__Z7impairei:
        pushl   %ebp
        movl    %esp, %ebp
        movl    8(%ebp), %eax
        andl    $1, %eax
        testl   %eax, %eax
        setne   %al
        movzbl  %al, %eax
        popl    %ebp
        ret

C:\travail>

Compilations sans éditions de lien - g++ -c

Nous le verrons lors de l'étude du makefile qu'il peut être intéressant de produire tous les fichiers objets sans passer encore par la phase d'édition de lien. Les fichiers objets sont également indispensables pour la fabrication de bibliothèques. Je rappelle qu'un fichier objet est un fichier compilé mais qui en plus est passé par la phase d'assemblage. Pour cela, il suffit d'utiliser l'option -c. Vous devez préciser également en paramètres de la commande g++ les fichiers qui devront être compilés et assemblés. Les fichiers objets portent l'extension ".o".

g++ -c impaire.cc paire.cc
--> impaire.o paire.o

Voici un scénario qui produit tous les fichiers objets qui pourront servir ensuite à l'édition de lien :

C:\travail>ls -l
total 4
-rwxrwxrwx 1 Emmanuel REMY Aucun  47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun  93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun  81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun 174 Aug 28 08:03 principal.cc

C:\travail>g++ -c principal.cc impaire.cc paire.cc

C:\travail>ls -l
total 9
-rwxrwxrwx 1 Emmanuel REMY Aucun   47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun  369 Aug 29 10:11 impaire.o
-rwxrwxrwx 1 Emmanuel REMY Aucun   93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun   81 Aug 28 08:03 paire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun  408 Aug 29 10:11 paire.o
-rwxrwxrwx 1 Emmanuel REMY Aucun  174 Aug 28 08:03 principal.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun 2167 Aug 29 10:11 principal.o

C:\travail>

 

Edition de lien à partir des fichiers compilés - g++ (sans options)

Pour produire un fichier exécutable, nous pouvons passer par les fichiers sources. Dans ce cas là, la commande g++ passe par toutes les phases de compilation jusqu'à l'édition de lien. Cela prend un certain temps. Si vous êtes sûr que vos sources n'ont pas changés, et que vous avez déjà produit vos fichiers objets, il est préférable de proposer directement l'édition de lien à partir de ces fichiers objets. Cela mettra beaucoup moins de temps à s'effectuer. Pour cela, au lieu de spécifier les sources dans la ligne de commande en paramètre de la comande g++, vous désignez à la place les fichiers objets :

g++ principal.o impaire.o paire.o
--> a.exe
g++ principal.o impaire.o paire.o -o calcul
--> calcul.exe

Voici donc comment proposer l'édition de lien et produire le programme calcul à partir des fichiers objets fabriqués à partir de la session précédente :

C:\travail>ls -l
total 9
-rwxrwxrwx 1 Emmanuel REMY Aucun   47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun  369 Aug 29 10:43 impaire.o
-rwxrwxrwx 1 Emmanuel REMY Aucun   93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun   81 Aug 28 08:03 paire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun  408 Aug 29 10:43 paire.o
-rwxrwxrwx 1 Emmanuel REMY Aucun  174 Aug 28 08:03 principal.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun 2167 Aug 29 10:43 principal.o

C:\travail>g++ principal.o impaire.o paire.o -o calcul

C:\travail>ls -l
total 481
-rwxrwxrwx 1 Emmanuel REMY Aucun 477569 Aug 29 10:44 calcul.exe
-rwxrwxrwx 1 Emmanuel REMY Aucun     47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun    369 Aug 29 10:43 impaire.o
-rwxrwxrwx 1 Emmanuel REMY Aucun     93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun     81 Aug 28 08:03 paire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun    408 Aug 29 10:43 paire.o
-rwxrwxrwx 1 Emmanuel REMY Aucun    174 Aug 28 08:03 principal.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun   2167 Aug 29 10:43 principal.o

C:\travail>calcul
valeur = 0

C:\travail>

 

Choix du chapitreTravailler avec les bibliothèques (archives)

Plutôt que de recommencer systématiquement un travail, il peut être avantageux de conserver les fichiers déjà compilés, qui font partis d'un même thème, dans un seul et même fichier. Par exemple, nous pouvons construire un certain nombre de fichiers séparés relatifs à des fonctions mathématiques. Il est alors judicieux de les archiver dans une bibliothèque commune dénommée mathématique.

Evidemment, nous aurions pu construire un seul fichier source qui comporte l'ensemble des fonctions mathématiques. Cette approche n'est pas souhaitable puisque lorsque vous modifier une seule fonction, vous devez alors recompiler l'ensemble des autres fonctions puisqu'elles font parties du même fichier source. L'idéal est de construire un fichier par fonction et ensuite de les rassembler dans une bibliothèque commune.

 

Fabriquer une archive - ar -r

Pour mettre en place une bibliothèque, nous devons utiliser la commande ar (diminutif de archive). Cette commande ne prend que les modules objets (fichiers déjà compilés et assemblés) qui portent donc l'extension ".o". L'archive produite délivre alors un fichier qui porte l'extension ".a".

ar -r mathematique.a impaire.o paire.o
--> mathematique.a
// La première fois, l'archive mathématique.a comporte donc deux modules objets : impaire.o et paire.o

Vous devez systématiquement indiquer le nom de l'archive en paramètre de la commande ar avec son extension. Si l'archive n'existe pas, elle est alors créée. Si l'archive existe déjà, les fichiers proposés en paramètres sont rajoutés à l'archive.

La commande ar, comme pour la commande g++ prend un certain nombre d'options. L'option -r spécifie que si un module objet existe déjà, il est tout simplement écraser au profit de la nouvelle version. Cette option spécifie également que les nouveaux modules objets sont placés à la fin de l'archive.

C:\travail>ls -l
total 4
-rwxrwxrwx 1 Emmanuel REMY Aucun  47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun  93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun  81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun 174 Aug 28 08:03 principal.cc

C:\travail>g++ -c impaire.cc paire.cc

C:\travail>ls -l
total 6
-rwxrwxrwx 1 Emmanuel REMY Aucun  47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun 369 Aug 29 16:00 impaire.o
-rwxrwxrwx 1 Emmanuel REMY Aucun  93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun  81 Aug 28 08:03 paire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun 408 Aug 29 16:00 paire.o
-rwxrwxrwx 1 Emmanuel REMY Aucun 174 Aug 28 08:03 principal.cc

C:\travail>ar -r mathematique.a impaire.o paire.o
ar: creating mathematique.a

C:\travail>ls -l
total 7
-rwxrwxrwx 1 Emmanuel REMY Aucun   47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun  369 Aug 29 16:00 impaire.o
-rw-rw-rw- 1 Emmanuel REMY Aucun 1002 Aug 29 16:00 mathematique.a
-rwxrwxrwx 1 Emmanuel REMY Aucun   93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun   81 Aug 28 08:03 paire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun  408 Aug 29 16:00 paire.o
-rwxrwxrwx 1 Emmanuel REMY Aucun  174 Aug 28 08:03 principal.cc

C:\travail>

 

Lister le contenu d'une archive - ar -t

Une fois que l'archive est construite, il est possible de vérifier son contenu après coup. L'option -t de la commande ar donne la liste des modules objets présent dans l'archive :

C:\travail>ar -t mathematique.a
impaire.o
paire.o

C:\travail>

 

Supprimer un module objet de l'archive - ar -d

Si un module objet vous encombre dans l'archive, vous pouvez toujours l'enlever de l'archive au moyen de l'option -d de la commande ar. Voici comment enlever le module paire.o que nous replaçons ensuite :

C:\travail>ar -d mathematique.a paire.o

C:\travail>ar -t mathematique.a
impaire.o

C:\travail>ar -r mathematique.a paire.o

C:\travail>ar -t mathematique.a
impaire.o
paire.o

C:\travail>

 

Extraire un fichier objet d'une archive - ar -x

Il est également possible d'extirper un module objet d'une archive et ainsi de le récupérer afin d'utiliser ce seul fichier pour d'autres projets ultérieurs. Prenez alors l'option -x de la commande ar.

C:\travail>ls -l
total 5
-rwxrwxrwx 1 Emmanuel REMY Aucun   47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun 1002 Aug 29 16:15 mathematique.a
-rwxrwxrwx 1 Emmanuel REMY Aucun   93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun   81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun  174 Aug 28 08:03 principal.cc

C:\travail>ar -t mathematique.a
impaire.o
paire.o

C:\travail>ar -x mathematique.a impaire.o

C:\travail>ls -l
total 6
-rwxrwxrwx 1 Emmanuel REMY Aucun   47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun  369 Aug 29 16:21 impaire.o
-rw-rw-rw- 1 Emmanuel REMY Aucun 1002 Aug 29 16:15 mathematique.a
-rwxrwxrwx 1 Emmanuel REMY Aucun   93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun   81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun  174 Aug 28 08:03 principal.cc

C:\travail>

 

Edition de lien à partir d'une archive - g++

L'édition de lien peut aussi bien prendre des modules objets séparés entre eux, ou bien prendre les mêmes archivés dans une bibliothèque. A l'aide de la commande g++, nous avons vu que nous pouvions avoir, aussi bien des fichiers sources que des fichiers déjà compilés. De même, il est également possible de prendre, en plus des fichiers sources ou objets en paramètre de la commande g++, des archives qui servirons pour la phase d'édition de lien.

C:\travail>ls -l
total 5
-rwxrwxrwx 1 Emmanuel REMY Aucun   47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun 1002 Aug 29 16:15 mathematique.a
-rwxrwxrwx 1 Emmanuel REMY Aucun   93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun   81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun  174 Aug 28 08:03 principal.cc

C:\travail>g++ -o calcul principal.cc mathematique.a

C:\travail>ls -l
total 477
-rwxrwxrwx 1 Emmanuel REMY Aucun 477569 Aug 29 16:30 calcul.exe
-rwxrwxrwx 1 Emmanuel REMY Aucun     47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 Emmanuel REMY Aucun   1002 Aug 29 16:15 mathematique.a
-rwxrwxrwx 1 Emmanuel REMY Aucun     93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 Emmanuel REMY Aucun     81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 Emmanuel REMY Aucun    174 Aug 28 08:03 principal.cc

C:\travail>calcul
valeur = 0

C:\travail>

 

Choix du chapitre Fichier de dépendance - makefile

Si vous disposez de beaucoup de fichiers sources pour développer un projet, il peut être fastidieux d'utiliser successivement plusieurs commandes g++ directement. Par ailleurs, si vous devez développer une archive en même temps que l'exécutable, le temps passé à écrire ces commandes peut être très long en regard de petites modifications exécutées sur un seul source. L'idéal est d'automatiser l'ensemble de ces tâches par l'intermédiaire de fichiers dénommés Makefiles.

Les Makefiles sont des fichiers, généralement appelés makefile ou Makefile, utilisés par le programme make pour exécuter un ensemble d'actions, comme la compilation d'un projet, l'archivage de document, la mise à jour de site, etc.

L'utilitaire make permet de mettre à jour un programme obtenu à partir d'un ensemble de modules distincts en prenant en plus en compte les dates de modification du programme à maintenir et des différents modules entrant dans la constitution de ce programme. L'utilisation de make suppose l'existence d'un fichier particulier appelé makefile contenant d'une part la description du graphe des liaisons entre les différents modules intervenant dans la constitution du programme à maintenir, et d'autre part les actions à réaliser pour remettre à jour ce programme (règles de construction).

 

Intérêt de disposer d'un makefile

Si vous considérez un très vaste projet composé de dizaines, voire de centaines de modules, vous n'êtes sans doute pas très impatient de recompiler tous ces modules chaque fois qu'une ligne de code est modifié et un test effectué. Imaginez devoir recompiler entièrement un noyau Linux après une petite modification du code source.

Il est surtout très difficile de déterminer les compilations à omettre, et l'omission de compilations indispensables entraînera de sérieux problèmes pas toujours faciles à détecter. La commande make est précisément destinée à ce genre de travail.

La commande make est capable de tirer des conclusions sur les dépendances existant entre divers fichiers. Les instructions de compilation sont enregistrés dans le fichier makefile. Par exemple, il n'est pas nécessaire de mémoriser tous les paramètres de ligne de commande utilisé pour un projet. Mieux encore, il n'est pas nécessaire de documenter à l'intention d'autrui ce qui vous a servi à construire ce projet.

 

Constitution d'un makefile

Un Makefile est un fichier constitué de plusieurs règles de la forme :

cible: dépendance
	commnandes

Attention : chaque commande doit être précédée d'une tabulation.
.

Lors de l'utilisation d'un tel fichier via la commande make la première règle rencontrée, ou la règle dont le nom est spécifié, est évaluée. L'évaluation d'une règle se fait en plusieurs étapes :

  1. Les dépendances sont analysées, si une dépendance est la cible d'une autre règle du Makefile, cette règle est à son tour évaluée.
  2. Lorsque l'ensemble des dépendances est analysé et si la cible ne correspond pas à un fichier existant ou si un fichier dépendance est plus récent que la règle, les différentes commandes sont exécutées.

 

Construction du premier Makefile

Rentrons tout de suite dans le vif du sujet pour bien comprendre le fonctionnement d'un makefile. Le premier makefile traitera de la construction de l'exécutable calcul sans passer par une archive.

makefile
calcul: impaire.o paire.o principal.o
g++ -o calcul impaire.o paire.o principal.o
impaire.o: impaire.cc
g++ -c impaire.cc
paire.o: paire.cc mathematique.h
g++ -c paire.cc
principal.o: principal.cc mathematique.h
g++ -c principal.cc

Regardons de plus près sur cet exemple comment fonctionne un Makefile :

  1. Nous cherchons d'abord à créer le fichier exécutable calcul.exe. La première dépendance, impaire.o est elle-même la cible d'une des régles de notre Makefile. Nous évaluons donc avant de poursuivre la règle calcul cette nouvelle règle liée à impaire.o.
  2. Comme cette fois-ci aucune dépendance de impaire.o n'est une règle. Aucune autre règle n'est à évaluer pour compléter celle-ci. Deux cas se présentent ici : soit le fichier impaire.cc est plus récent que le fichier impaire.o, la commande est alors exécutée et impaire.o est construit, soit impaire.o est plus récent que impaire.cc et la commande n'est pas exécutée. L'évalution de la règle impaire.o est ainsi terminée.
  3. Nous pouvons dès lors examiner les autres dépendances de calcul (paire.o et principal.o) de la même manière puis, si nécessaire, la commande de la règle calcul est exécutée et calcul est enfin construit.

Nous pouvons nous demander pourquoi dans notre makefile, nous passons par la construction systématique des modules objets et pourquoi ne pas s'en tenir à une seule ligne de commande pour tout construire d'un coup ? C'est justement pour utiliser l'avantage des makefiles. Il est absolument nécessaire de conserver un fichier de compilation afin que par la suite nous puissions contrôler la date de compilation par rapport à un éventuel changement d'un des codes sources. Ainsi, seuls les fichiers qui auront subit une modification seront recompiler mais pas les autres. Finalement, le temps de construction d'un projet s'en trouve toujours le plus réduit possible.

 

Mise en pratique de notre premier makefile

Nous allons maintenant mettre en oeuvre notre premier makefile afin de bien visualiser tout le processus que nous venons de décrire. Je rappelle que pour exécuter le makefile, il faut passer par la commande make.

M:\travail>ls -l
total 5
-rwxrwxrwx 1 HP_Propriétaire Aucun   47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun 246 Aug 30 11:03 makefile
-rwxrwxrwx 1 HP_Propriétaire Aucun   93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 HP_Propriétaire Aucun   81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun 174 Aug 28 08:03 principal.cc

M:\travail>make
g++ -c impaire.cc
g++ -c paire.cc
g++ -c principal.cc
g++ -o calcul impaire.o paire.o principal.o

M:\travail>ls -l
total 523
-rwxrwxrwx 1 HP_Propriétaire Aucun 477569 Aug 30 11:08 calcul.exe
-rwxrwxrwx 1 HP_Propriétaire Aucun          47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 HP_Propriétaire Aucun         369 Aug 30 11:08 impaire.o
-rwxrwxrwx 1 HP_Propriétaire Aucun       246 Aug 30 11:03 makefile
-rwxrwxrwx 1 HP_Propriétaire Aucun         93 Aug 26 14:45 mathematique.h
-rwxrwxrwx 1 HP_Propriétaire Aucun         81 Aug 28 08:03 paire.cc
-rw-rw-rw- 1 HP_Propriétaire Aucun        408 Aug 30 11:08 paire.o
-rwxrwxrwx 1 HP_Propriétaire Aucun      174 Aug 28 08:03 principal.cc
-rw-rw-rw- 1 HP_Propriétaire Aucun     2167 Aug 30 11:08 principal.o

M:\travail>calcul
valeur = 0

M:\travail>

Vu qu'il s'agit de notre première construction, toutes les cibles sont exécutées avec la fabrication des modules objets afin de faire appel ensuite à l'édition de lien.

Lorsque nous lançons la commande make, l'utilitaire vérifie la présence du fichier makefile. S'il n'est pas présent, l'utilitaire s'arrête sans rien exécuter. Dans le cas contraire, il ouvre le makefile et réagit à toutes les dépendances décrites dans ce fichier.

Relançons tout de suite après la commande make :

M:\travail>make
make: `calcul' is up to date.

M:\travail>

Vous remarquez que cette fois-ci aucune compilation, ni d'édition de lien ne sont exécutées puisqu'il y a eu aucune modification sur l'ensemble des fichiers sources.

Modifions maintenant le source de principal.cc en rajoutant un espace quelque part et relancer la commande make :

M:\travail>make
g++ -c principal.cc
g++ -o calcul impaire.o paire.o principal.o

M:\travail>

Cette fois-ci, nous devons reconstruire le module principal.o puisque le source correspondant a été modifié. Par contre, il n'est pas utile de toucher à impaire.o et paire.o. Ensuite, nous sommes obligé de passer par l'édition de lien.

Pour terminer ce premier test, changeons cette fois-ci le source du fichier en-tête mathematique.h et relançons la commande make :

M:\travail>make
g++ -c paire.cc
g++ -c principal.cc
g++ -o calcul impaire.o paire.o principal.o

M:\travail>

Deux fichiers sont influencés par la modification de mathematique.h, paire.o et principal.o. Il faut donc les recompiler et faire ensuite appel à l'édition de lien.

 

La commande make

Nous venons de voir que la commande make permet d'interpréter un fichier de dépendance entre les différents éléments nécessaires à la création d'un projet. Ce fichier est très souvent appelé « makefile » mais il est possible de choisir un autre nom de fichier ou d'utiliser plusieurs fichiers de projet.

Quelque soit le nom du fichier choisit, il contient les relations entre fichiers qui permettent d'établir les dépendances nécessaires à la création d'autres fichiers. Si, pour créer un fichier A, il faut utiliser un fichier B, alors il va d'abord falloir créer le fichier B. Le travail de make est essentiellement de vérifier les dates des fichiers pour déterminer quels sont ceux qui sont à jour et ceux qu'il faut recréer afin de générer le projet. Pour chacun des fichiers à recréer, une ligne de commande est exécutée.

En réalité, make peut être utilisé dans un autre contexte que la programmation : il permet d'effectuer des commandes de mises à jour de fichiers qui dépendent de la mise à jour d'autres fichiers.

Jusqu'à présent, nous avons utilisé la commande make sans option et sans paramètres. Les deux sont possibles. Voici d'ailleurs la syntaxe générale :

make -f fichier cible

où :

  1. fichier : indique le fichier de dépendance à traiter à la place du fichier par défaut makefile. Il faut alors placer l'option -f juste devant le nom du fichier.
  2. cible : pointe directement la cible à atteindre dans le fichier de dépendance. En effet, il est possible de traiter plusieurs projets dans un même fichier de dépendance.

 

Travailler avec deux fichiers de dépendance - make -f fichier de dépendance

Nous allons maintenant travail avec deux makefiles. Le premier, que je nomme projet, est le makefile avec lequel nous avons déjà travailler et qui permet de fabriquer l'exécutable calcul sans passer par une archive. Le deuxième, que je nomme archive, aboutit au même résultat mais fabrique et utilise en même temps la bibliothèque mathematique.a.

projet
calcul: impaire.o paire.o principal.o
g++ -o calcul impaire.o paire.o principal.o
impaire.o: impaire.cc
g++ -c impaire.cc
paire.o: paire.cc mathematique.h
g++ -c paire.cc
principal.o: principal.cc mathematique.h
g++ -c principal.cc
archive
calcul: principal.o mathematique.a
        g++ -o calcul principal.o mathematique.a
mathematique.a: impaire.o paire.o
        ar -r mathematique.a impaire.o paire.o
impaire.o: impaire.cc
        g++ -c impaire.cc
paire.o: paire.cc mathematique.h
        g++ -c paire.cc
principal.o: principal.cc mathematique.h
        g++ -c principal.cc

Voici un scénario qui traite du fichier de dépendance archive qui fabrique d'abord la bibliothèque et ensuite utilise cette bibliothèque afin de mettre en oeuvre l'exécutable calcul :

M:\travail>ls -l
total 6
-rwxrwxrwx 1 HP_Propriétaire Aucun 314 Aug 31 09:43 archive
-rwxrwxrwx 1 HP_Propriétaire Aucun   47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun 100 Aug 30 11:50 mathematique.h
-rwxrwxrwx 1 HP_Propriétaire Aucun   81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun 174 Aug 30 11:25 principal.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun 246 Aug 30 11:03 projet

M:\travail>make -f archive
g++ -c principal.cc
g++ -c impaire.cc
g++ -c paire.cc
ar -r mathematique.a impaire.o paire.o
ar: creating mathematique.a
g++ -o calcul principal.o mathematique.a

M:\travail>ls -l
total 528
-rwxrwxrwx 1 HP_Propriétaire Aucun        314 Aug 31 09:43 archive
-rwxrwxrwx 1 HP_Propriétaire Aucun 477569 Aug 31 09:47 calcul.exe
-rwxrwxrwx 1 HP_Propriétaire Aucun          47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 HP_Propriétaire Aucun         369 Aug 31 09:47 impaire.o
-rw-rw-rw- 1 HP_Propriétaire Aucun       1002 Aug 31 09:47 mathematique.a
-rwxrwxrwx 1 HP_Propriétaire Aucun        100 Aug 30 11:50 mathematique.h
-rwxrwxrwx 1 HP_Propriétaire Aucun          81 Aug 28 08:03 paire.cc
-rw-rw-rw- 1 HP_Propriétaire Aucun         408 Aug 31 09:47 paire.o
-rwxrwxrwx 1 HP_Propriétaire Aucun       174 Aug 30 11:25 principal.cc
-rw-rw-rw- 1 HP_Propriétaire Aucun      2167 Aug 31 09:47 principal.o
-rwxrwxrwx 1 HP_Propriétaire Aucun       246 Aug 30 11:03 projet

M:\travail>calcul
valeur = 0

M:\travail>ar -t mathematique.a
impaire.o
paire.o

M:\travail>

Pour lancer le fichier de dépendance souhaité, il suffit de le placer en paramètre de la commande make. N'oubliez pas alors d'utiliser l'option -f.

Nous pouvons aussi travailler avec l'autre makefile projet :

M:\travail>make -f projet
make: `calcul' is up to date.

M:\travail>

calcul a déjà été construit au travers du makefile archive, comme nous n'avons changé aucun des sources, l'exécutable est donc tout à fait à jour.

A titre d'exemple, modifions le fichier en-tête mathematique.h pour voir les conséquences sur le fichier de dépendance archive :

M:\travail>make -f archive
g++ -c principal.cc
g++ -c paire.cc
ar -r mathematique.a impaire.o paire.o
g++ -o calcul principal.o mathematique.a

M:\travail>

mathematique.h influence paire.o et principal.o. Du coup, il est nécessaire de reconstruire l'archive ainsi que l'exécutable en passant par l'édition de lien.

 

Travailler avec des cibles - make cible

Plutôt que de prendre la totalité d'un fichier de dépendance, nous pouvons demander à travailler qu'avec une partie. Il faut alors préciser la cible à atteindre en paramètre de la commande make.

M:\travail>ls -l
total 6
-rwxrwxrwx 1 HP_Propriétaire Aucun 314 Aug 31 09:43 archive
-rwxrwxrwx 1 HP_Propriétaire Aucun   47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun 100 Aug 31 10:07 mathematique.h
-rwxrwxrwx 1 HP_Propriétaire Aucun   81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun 174 Aug 30 11:25 principal.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun 246 Aug 30 11:03 projet

M:\travail>make -f archive mathematique.a
g++ -c impaire.cc
g++ -c paire.cc
ar -r mathematique.a impaire.o paire.o
ar: creating mathematique.a

M:\travail>ls -l
total 12
-rwxrwxrwx 1 HP_Propriétaire Aucun  314 Aug 31 09:43 archive
-rwxrwxrwx 1 HP_Propriétaire Aucun    47 Aug 26 14:51 impaire.cc
-rw-rw-rw- 1 HP_Propriétaire Aucun   369 Aug 31 10:11 impaire.o
-rw-rw-rw- 1 HP_Propriétaire Aucun 1002 Aug 31 10:11 mathematique.a
-rwxrwxrwx 1 HP_Propriétaire Aucun  100 Aug 31 10:07 mathematique.h
-rwxrwxrwx 1 HP_Propriétaire Aucun    81 Aug 28 08:03 paire.cc
-rw-rw-rw- 1 HP_Propriétaire Aucun   408 Aug 31 10:11 paire.o
-rwxrwxrwx 1 HP_Propriétaire Aucun  174 Aug 30 11:25 principal.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun  246 Aug 30 11:03 projet

M:\travail>ar -t mathematique.a
impaire.o
paire.o

M:\travail>

Cette fois-ci l'exécutable calcul n'est pas créé. Seule l'archive mathematique.a a été construite.
.

Il est tout a fait possible de solliciter plusieurs cibles avec la même commande.
.

 

Un seul makefile avec possibilité de construire ou de tout reconstruire

Avec toutes les possibilités que nous venons de découvrir, nous pouvons élaborer notre makefile pour qu'il soit capable soit de construire une application normalement, comme nous avons eu l'occasion de le voir, ou au contraire pour qu'il soit capable de tout reconstruire même si aucune modification n'a été apportée dans l'un des fichiers sources. Auquel cas, il est d'abord nécessaire d'effacer tous les fichiers de construction, et ensuite de faire appel à la construction normale. Voici une exemple de makefile qui prend en compte ces nouvelles caractéristiques :

makefile
construire: calcul
calcul: principal.o mathematique.a
        g++ -o calcul principal.o mathematique.a
mathematique.a: impaire.o paire.o
        ar -r mathematique.a impaire.o paire.o
impaire.o: impaire.cc
        g++ -c impaire.cc
paire.o: paire.cc mathematique.h
        g++ -c paire.cc
principal.o: principal.cc mathematique.h
        g++ -c principal.cc
effacer:
        rm -f *.o
        rm -f calcul.exe mathematique.a
reconstruire: effacer construire

Voici un scénario qui d'abord construit le projet et ensuite demande de le reconstruire :

M:\travail>ls -l
total 5
-rwxrwxrwx 1 HP_Propriétaire Aucun  47 Aug 26 14:51 impaire.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun 424 Aug 31 10:54 makefile
-rwxrwxrwx 1 HP_Propriétaire Aucun 100 Aug 31 10:07 mathematique.h
-rwxrwxrwx 1 HP_Propriétaire Aucun  81 Aug 28 08:03 paire.cc
-rwxrwxrwx 1 HP_Propriétaire Aucun 174 Aug 30 11:25 principal.cc

M:\travail>make
g++ -c principal.cc
g++ -c impaire.cc
g++ -c paire.cc
ar -r mathematique.a impaire.o paire.o
ar: creating mathematique.a
g++ -o calcul principal.o mathematique.a

M:\travail>make
make: Nothing to be done for `construire'.

M:\travail>make reconstruire
rm -f *.o
rm -f calcul.exe mathematique.a
g++ -c principal.cc
g++ -c impaire.cc
g++ -c paire.cc
ar -r mathematique.a impaire.o paire.o
ar: creating mathematique.a
g++ -o calcul principal.o mathematique.a

M:\travail>

Pour la phase de construction, il n'est pas indispensable de spécifier la cible construire puisque c'est celle qui est écrite en premier. Lorsque nous sollicitons make une deuxième fois, et vu que nous n'avons effectué aucune modification dans aucun des fichiers sources, l'utilitaire nous indique qu'il n'a rien à faire de particulier par rapport à construire. Lorsque nous faisons explicitement appel à la cible reconstruire, cette dernière propose en premier lieu l'effacement de tous les fichiers autre que les sources et ensuite relance la construction normale.