Articles

GCC et Make

GCC (GNU Compiler Collection)

Un bref historique et une introduction à GCC

Le compilateur original GNU C (GCC) est développé par Richard Stallman, le fondateur du projet GNU. Richard Stallman a fondé le projet GNU en 1984 pour créer un système d’exploitation complet de type Unix sous forme de logiciel libre, afin de promouvoir la liberté et la coopération entre les utilisateurs d’ordinateurs et les programmeurs.

GCC, anciennement pour « GNU C Compiler », s’est développé au fil du temps pour supporter de nombreux langages tels que C (gcc), C++ (g++), Objective-C, Objective-C++, Java (gcj), Fortran (gfortran), Ada (gnat), Go (gccgo), OpenMP, Cilk Plus et OpenAcc. Il est désormais désigné sous le nom de « GNU Compiler Collection ». Le site mère de GCC est http://gcc.gnu.org/. La version actuelle est GCC 7.3, publiée le 2018-01-25.

GCC est un composant clé de ce qu’on appelle la « GNU Toolchain », pour le développement d’applications et l’écriture de systèmes d’exploitation. La GNU Toolchain comprend :

  1. GNU Compiler Collection (GCC) : une suite de compilateurs qui prend en charge de nombreux langages, tels que C/C++ et Objective-C/C++.
  2. GNU Make : un outil d’automatisation pour la compilation et la construction d’applications.
  3. GNU Binutils : une suite d’outils utilitaires binaires, notamment un éditeur de liens et un assembleur.
  4. GNU Debugger (GDB).
  5. GNU Autotools : Un système de construction comprenant Autoconf, Autoheader, Automake et Libtool.
  6. GNU Bison : un générateur d’analyseur (similaire à lex et yacc).

GCC est portable et fonctionne dans de nombreuses plateformes d’exploitation. GCC (et GNU Toolchain) est actuellement disponible sur tous les Unix. Ils sont également portés sur Windows (par Cygwin, MinGW et MinGW-W64). GCC est également un compilateur croisé, pour produire des exécutables sur différentes plateformes.

Versions de GCC

Les différentes versions de GCC sont:

  • GCC version 1 (1987) : Version initiale qui supporte le C.
  • GCC version 2 (1992) : supporte le C++.
  • GCC version 3 (2001) : incorpore ECGS (Experimental GNU Compiler System), avec une meilleure optimisation.
  • GCC version 4 (2005):
  • GCC version 5 (2015):
  • GCC version 6 (2016):
  • GCC version 7 (2017):
Support des standards C++

Il existe différents standards C++ :

  • C++98
  • C++11 (aka C++0x)
  • C++14 (aka C++1y)
  • C++17 (aka C++1z)
  • C++2a (prochaine norme prévue en 2020)

Le mode par défaut est C++98 pour les versions de GCC antérieures à 6.1, et C++14 pour GCC 6.1 et plus. Vous pouvez utiliser l’indicateur de ligne de commande -std pour spécifier explicitement la norme C++. Par exemple,

  • -std=c++98, ou -std=gnu++98 (C++98 avec extensions GNU)
  • -std=c++11, ou -std=gnu++11 (C++11 avec extensions GNU)
  • -std=c++14, ou -std=gnu++14 (C++14 avec extensions GNU), mode par défaut pour GCC 6.1 et plus.
  • -std=c++17, ou -std=gnu++17 (C++17 avec extensions GNU), expérimental.
  • -std=c++2a, ou -std=gnu++2a (C++2a avec extensions GNU), expérimental.

Installation de GCC sur les Unix

La chaîne d’outils GNU, y compris GCC, est incluse dans tous les Unix. C’est le compilateur standard pour la plupart des systèmes d’exploitation de type Unix.

Installation de GCC sur Mac OS X

Ouvrir un Terminal, et entrer « gcc --version« . Si gcc n’est pas installé, le système vous invitera à installer gcc.

$ gcc --version......Target: x86_64-apple-darwin14.5.0 // 64-bit target codesThread model: posix

Installation de GCC sur Windows

Pour Windows, vous pourriez soit installer Cygwin GCC, MinGW GCC ou MinGW-W64 GCC. Lisez « Comment installer Cygwin et MinGW ».

  • Cygwin GCC : Cygwin est un environnement de type Unix et une interface de ligne de commande pour Microsoft Windows. Cygwin est énorme et comprend la plupart des outils et utilitaires Unix. Il comprenait également l’interpréteur de commandes Bash, couramment utilisé.
  • MinGW : MinGW (Minimalist GNU for Windows) est un portage de la GNU Compiler Collection (GCC) et de GNU Binutils pour une utilisation sous Windows. Il inclut également MSYS (Minimal System), qui est essentiellement un shell Bourne (bash).
  • MinGW-W64 : un fork de MinGW qui prend en charge les fenêtres 32 bits et 64 bits.
Divers GCC sous Cygwin

Il existe de nombreux GCC sous Cygain/MinGW. Pour différencier ces variations, vous devez comprendre les points suivants :

  • Windows/Intel utilise ces jeux d’instructions : x86 est un jeu d’instructions 32 bits ; i868 est une version améliorée 32 bits de x86 ; x86_64 (ou amd64) est un jeu d’instructions 64 bits.
  • Les compilateurs/programmes 32 bits peuvent fonctionner sur Windows 32 bits ou 64 bits (rétrocompatible), mais le compilateur 64 bits ne peut fonctionner que sur Windows 64 bits.
  • Les compilateurs 64 bits peuvent produire une cible de 32 bits ou de 64 bits.
  • Si vous utilisez le GCC de Cygwin, la cible pourrait être Windows natif ou Cygwin. Si la cible est Windows natif, le code peut être distribué et exécuté sous Windows. Cependant, si la cible est Cygwin, pour distribuer, vous devez distribuer l’environnement d’exécution Cygwin (cygwin1.dll). Cela s’explique par le fait que Cygwin est un émulateur Unix sous Windows.

MinGW-W64 Target 32/64-bit Native Windows

Le MinGW-W64 (un fork de MinGW, disponible à l’adresse http://mingw-w64.org/doku.php) prend en charge la cible de Windows native 32 bits et 64 bits. Vous pouvez installer « MinGW-W64 » sous « Cygwin » en sélectionnant ces paquets (sous la catégorie « devel ») :

  • mingw64-x86_64-gcc-core : compilateur C 64 bits pour cible de Windows 64 bits natif. L’exécutable est « x86_64-w64-mingw32-gcc« .
  • mingw64-x86_64-gcc-g++ : compilateur C++ 64 bits pour cible de Windows 64 bits natif. L’exécutable est « x86_64-w64-mingw32-g++« .
  • mingw64-i686-gcc-core : compilateur C 64 bits pour cible de Windows 32 bits natif. L’exécutable est « i686-w64-mingw32-gcc« .
  • mingw64-i686-gcc-g++ : compilateur C++ 64 bits pour cible de Windows 32 bits natif. L’exécutable est « i686-w64-mingw32-g++« .

Notes :

  • Je vous suggère d’installer « mingw64-x86_64-gcc-core » et « mingw64-x86_64-gcc-g++ » pour fournir des codes natifs de Windows 64 bits, mais ignorez « mingw64-i686-gcc-core » et « mingw64-i686-gcc-g++« , sauf si vous devez produire des applications Windows 32 bits.
  • Pour JNI (Java Native Interface) en Java 64 bits, vous devez utiliser « x86_64-w64-mingw32-gcc » ou « x86_64-w64-mingw32-g++ » pour produire du code Windows natif 64 bits.

Exécutez les exécutables et vérifiez les versions :

// Target 64-bit native Windows$ x86_64-w64-mingw32-gcc --version
x86_64-w64-mingw32-gcc (GCC) 6.4.0$ x86_64-w64-mingw32-gcc -v
Using built-in specs.
COLLECT_GCC=x86_64-w64-mingw32-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-w64-mingw32/6.4.0/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: .....
Thread model: posix
gcc version 6.4.0 (GCC)$ x86_64-w64-mingw32-g++ --version
x86_64-w64-mingw32-g++ (GCC) 6.4.0// Target 32-bit native Windows$ i686-w64-mingw32-gcc --version
i686-w64-mingw32-gcc (GCC) 6.4.0
$ i686-w64-mingw32-g++ --version
i686-w64-mingw32-g++ (GCC) 6.4.0
Autres GCC dans Cygwin

Les autres paquets GCC dans Cygwin sont :

  • gcc-core, gcc-g++ : le compilateur C/C++ de base 64 bits cible Cygwin 64 bits. Vous devriez probablement installer ces deux paquets également. Cependant, pour distribuer le code produit, vous devez distribuer Cygwin Runtime Environment (cygwin1.dll). En effet, Cygwin est un émulateur Unix sous Windows.
  • cygwin32-gcc-core, cygwin32-gcc-g++ : Ancien compilateur C/C++ 32 bits pour la cible Cygwin 32 bits (Obsoleted by gcc-code et gcc-g++ ?).
  • mingw-gcc-core, mingw-gcc-g++ : Ancien compilateur MinGW 32 bits C/C++ pour Windows 32 bits (rendu obsolète par les paquets MinGW-W64 ?).

Post Installation

Versions

Vous pourriez afficher la version de GCC via l’option --version :

$ gcc --versiongcc (GCC) 6.4.0$ g++ --version g++ (GCC) 6.4.0

Plus de détails peuvent être obtenus via -v option, par exemple,

$ gcc -vUsing built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/6.4.0/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: ......
Thread model: posix
gcc version 6.4.0 (GCC)$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-cygwin/6.4.0/lto-wrapper.exe
Target: x86_64-pc-cygwin
Configured with: ......
Thread model: posix
gcc version 6.4.0 (GCC)
Help

Vous pouvez obtenir le manuel d’aide via l’option --help. Par exemple,

$ gcc --help
Pages de manuel

Vous pouvez lire les pages de manuel de GCC (ou pages de manuel) via l’utilitaire man:

$ man gcc// or$ man g++// Press space key for next page, or 'q' to quit.

Lire les pages de manuel sous le shell CMD ou Bash peut être difficile. Vous pourriez générer un fichier texte via:

$ man gcc | col -b > gcc.txt

L’utilitaire col est nécessaire pour dépouiller le retour arrière. (Pour Cygwin, il est disponible dans « Utils », paquet « util-linux ».)

Alternativement, vous pourriez chercher une page de manuel en ligne, par ex, http://linux.die.net/man/1/gcc.

Les pages de manuel de GCC sont conservées sous « usr/share/man/man1« .

$ whereis gccgcc: /usr/bin/gcc.exe /usr/lib/gcc /usr/share/man/man1/gcc.1.gz

Démarrer

Le compilateur GNU C et C++ s’appellent respectivement gcc et g++.

Compiler/Lier un programme simple en C – hello.c

Vous trouverez ci-dessous le programme C Hello-world hello.c :

.

1234567
// hello.c#include <stdio.h> int main() { printf("Hello, world!\n"); return 0;}

Pour compiler le hello.c :

> gcc hello.c // Compile and link source file hello.c into executable a.exe (Windows) or a (Unixes)

L’exécutable de sortie par défaut s’appelle « a.exe« . (Windows) ou « a.out » (Unix et Mac OS X).

Pour exécuter le programme:

// (Windows) In CMD shell> a// (Unixes / Mac OS X) In Bash Shell - include the current path (./)$ chmod a+x a.out$ ./a.out

Notes pour Unix et Bash Shell:

  • Dans le shell Bash, le PATH par défaut n’inclut pas le répertoire de travail actuel. Par conséquent, vous devez inclure le chemin actuel (./) dans la commande. (Windows inclut automatiquement le répertoire courant dans le PATH ; alors que les Unix ne le font pas – vous devez inclure le répertoire courant explicitement dans le PATH.)
  • Vous devez également inclure l’extension du fichier, le cas échéant, c’est-à-dire , « ./a.out« .
  • Dans les Unix, le fichier de sortie pourrait être « a.out » ou simplement « a« . En outre, vous devez attribuer le mode fichier exécutable (x) au fichier exécutable « a.out« , via la commande « chmod a+x filename » (ajouter le mode fichier exécutable « +x » à tous les utilisateurs « a+x« ).

Pour spécifier le nom du fichier de sortie, utilisez l’option -o:

// (Windows) In CMD shell> gcc -o hello.exe hello.c // Compile and link source file hello.c into executable hello.exe> hello // Execute hello.exe under CMD shell// (Unixes / Mac OS X) In Bash shell$ gcc -o hello hello.c$ chmod a+x hello$ ./hello

NOTE pour les Unix :

  • Dans les Unix, on omet généralement l’extension de fichier .exe (destinée à Windows uniquement), et on nomme simplement l’exécutable de sortie hello (via la commande « gcc -o hello hello.c« .
  • Vous devez attribuer le mode de fichier exécutable via la commande « chmod a+x hello« .
Compiler/Lier un programme C++ simple – hello.cpp
12345678
// hello.cpp#include <iostream>using namespace std; int main() { cout << "Hello, world!" << endl; return 0;}

Vous devez utiliser g++ pour compiler le programme C++, comme suit . Nous utilisons l’option -o pour spécifier le nom du fichier de sortie.

// (Windows) In CMD shell> g++ -o hello.exe hello.cpp // Compile and link source hello.cpp into executable hello.exe> hello // Execute under CMD shell// (Unixes / Mac OS X) In Bash shell$ g++ -o hello hello.cpp$ chmod a+x hello$ ./hello
Plus d’options du compilateur GCC

Les quelques options du compilateur GCC couramment utilisées sont :

$ g++ -Wall -g -o Hello.exe Hello.cpp
  • -o : spécifie le nom du fichier exécutable de sortie.
  • -Wall : imprime « all« . Messages d’avertissement.
  • -g : génère des informations de débogage symbolique supplémentaires à utiliser avec gdb débogueur.
Compiler et lier séparément

La commande ci-dessus compile le fichier source en fichier objet et link avec les autres fichiers objets et les bibliothèques système en exécutable en une seule étape. Vous pouvez séparer la compilation et la liaison en deux étapes comme suit :

// Compile-only with -c option> g++ -c -Wall -g Hello.cpp// Link object file(s) into an executable> g++ -g -o Hello.exe Hello.o

Les options sont :

  • -c : Compiler dans le fichier objet « Hello.o« . Par défaut, le fichier objet porte le même nom que le fichier source avec l’extension « .o« . (il n’est pas nécessaire de spécifier l’option -o). Pas de liaison avec d’autres fichiers objets ou bibliothèques.
  • La liaison est effectuée lorsque le fichier d’entrée sont des fichiers objets « .o » (au lieu du fichier source « .cpp » ou « .c« ). GCC utilise un programme d’édition de liens distinct (appelé ld.exe) pour effectuer l’édition de liens.
Compiler et lier plusieurs fichiers sources

Supposons que votre programme possède deux fichiers sources : file1.cppfile2.cpp. Vous pourriez les compiler tous en une seule commande :

> g++ -o myprog.exe file1.cpp file2.cpp 

Cependant, nous compilons généralement chacun des fichiers sources séparément en fichier objet, et les lions ensemble dans une étape ultérieure. Dans ce cas, les modifications d’un fichier ne nécessitent pas la recompilation des autres fichiers.

> g++ -c file1.cpp> g++ -c file2.cpp> g++ -o myprog.exe file1.o file2.o
Compiler dans une bibliothèque partagée

Pour compiler et lier un programme C/C++ dans une bibliothèque partagée (".dll" sous Windows, ".so" sous Unixes), utilisez l’option -shared. Lire par exemple « Java Native Interface ».

Processus de compilation de GCC

GCC compile un programme C/C++ en exécutable en 4 étapes comme le montre le schéma ci-dessus. Par exemple, un « gcc -o hello.exe hello.c » s’effectue comme suit :

  1. Pré-traitement : via le préprocesseur GNU C (cpp.exe), qui inclut les en-têtes (#include) et développe les macros (#define
    > cpp hello.c > hello.i

    Le fichier intermédiaire résultant « hello.i » contient le code source étendu.

  2. Compilation : Le compilateur compile le code source prétraité en code d’assemblage pour un processeur spécifique.
    > gcc -S hello.i

    L’option -S spécifie de produire du code assembleur, au lieu du code objet. Le fichier d’assemblage résultant est « hello.s« .

  3. Ensembleur : L’assembleur (as.exe) convertit le code d’assemblage en code machine dans le fichier objet « hello.o
    > as -o hello.o hello.s
  4. Lieur : Enfin, le linker (ld.exe) lie le code objet avec le code de la bibliothèque pour produire un fichier exécutable « hello.exe
    > ld -o hello.exe hello.o ...libraries...
Mode verbose (-v)

Vous pouvez voir le processus de compilation détaillé en activant l’option -v (verbose). Par exemple,

> gcc -v -o hello.exe hello.c
Définir une macro (-D)

Vous pouvez utiliser l’option -Dname pour définir une macro, ou -Dname=value pour définir une macro avec une valeur. Le value doit être placé entre guillemets s’il contient des espaces.

En-têtes (.h), bibliothèques statiques (.lib, .a) et bibliothèque partagée (.dll, .so)

Bibliothèque statique vs bibliothèque partagée

Une bibliothèque est une collection de fichiers objets précompilés qui peuvent être liés à vos programmes via le linker. Les exemples sont les fonctions système telles que printf() et sqrt().

Il existe deux types de bibliothèques externes : la bibliothèque statique et la bibliothèque partagée.

  1. Une bibliothèque statique a une extension de fichier de « .a » (fichier d’archive) sous Unix ou « .lib » (bibliothèque) sous Windows. Lorsque votre programme est lié à une bibliothèque statique, le code machine des fonctions externes utilisées dans votre programme est copié dans l’exécutable. Une bibliothèque statique peut être créée via le programme d’archive « ar.exe« .
  2. Une bibliothèque partagée a pour extension de fichier « .so » (objets partagés) sous Unix ou « .dll » (bibliothèque de liens dynamiques) dans Windows. Lorsque votre programme est lié à une bibliothèque partagée, seule une petite table est créée dans l’exécutable. Avant que l’exécutable ne commence à fonctionner, le système d’exploitation charge le code machine nécessaire aux fonctions externes – un processus connu sous le nom de liaison dynamique. La liaison dynamique permet de réduire la taille des fichiers exécutables et d’économiser de l’espace disque, car une seule copie d’une bibliothèque peut être partagée entre plusieurs programmes. En outre, la plupart des systèmes d’exploitation permettent à tous les programmes en cours d’exécution d’utiliser une seule copie d’une bibliothèque partagée en mémoire, ce qui permet d’économiser de la mémoire. Les codes de la bibliothèque partagée peuvent être mis à jour sans avoir à recompiler votre programme.

En raison de l’avantage de la liaison dynamique, GCC, par défaut, établit des liens vers la bibliothèque partagée si elle est disponible.

Vous pouvez énumérer le contenu d’une bibliothèque via « nm filename« .

Recherche de fichiers d’en-tête et de bibliothèques (-I, -L et -l)

Lors de la compilation du programme, le compilateur a besoin des fichiers d’en-tête pour compiler les codes sources ; l’éditeur de liens a besoin des bibliothèques pour résoudre les références externes d’autres fichiers objets ou bibliothèques. Le compilateur et l’éditeur de liens ne trouveront pas les en-têtes/bibliothèques à moins que vous ne définissiez les options appropriées, ce qui n’est pas évident pour un utilisateur novice.

Pour chacun des en-têtes utilisés dans votre source (via les directives #include), le compilateur recherche ces en-têtes dans ce qu’on appelle les include-paths. Les include-paths sont spécifiés via l’option -Idir (ou la variable d’environnement CPATH). Le nom de fichier de l’en-tête étant connu (par exemple, iostream.hstdio.h), le compilateur n’a besoin que des répertoires.

Le linker recherche dans ce qu’on appelle les library-paths les bibliothèques nécessaires pour lier le programme en un exécutable. Le library-path est spécifié via l’option -Ldir (majuscule 'L' suivie du chemin du répertoire) (ou variable d’environnement LIBRARY_PATH). En outre, vous devez également spécifier le nom de la bibliothèque. Sous Unix, la bibliothèque libxxx.a est spécifiée via l’option -lxxx (lettre minuscule 'l', sans le préfixe « lib » et l’extension ".a« ). Sous Windows, fournissez le nom complet tel que -lxxx.lib. L’éditeur de liens doit connaître à la fois les répertoires et les noms des bibliothèques. Par conséquent, deux options doivent être spécifiées.

Paths d’inclusion, chemins de bibliothèque et bibliothèques par défaut

Essayez de lister les chemins d’inclusion par défaut de votre système utilisés par le « Préprocesseur GNU C » via « cpp -v » :

> cpp -v......#include "..." search starts here:#include <...> search starts here: /usr/lib/gcc/x86_64-pc-cygwin/6.4.0/include
/usr/include
/usr/lib/gcc/x86_64-pc-cygwin/6.4.0/../../../../lib/../include/w32api

Tentez d’exécuter la compilation en mode verbeux (-v) pour étudier les library-paths (-L) et les bibliothèques (-l) utilisés dans votre système :

> gcc -v -o hello.exe hello.c......-L/usr/lib/gcc/x86_64-pc-cygwin/6.4.0-L/usr/x86_64-pc-cygwin/lib-L/usr/lib-L/lib-lgcc_s // libgcc_s.a-lgcc // libgcc.a-lcygwin // libcygwin.a-ladvapi32 // libadvapi32.a-lshell32 // libshell32.a-luser32 // libuser32.a-lkernel32 // libkernel32.a

Eclipse CDT : Dans Eclipse CDT, vous pouvez définir les chemins d’inclusion, les chemins de bibliothèque et les bibliothèques en cliquant avec le bouton droit de la souris sur le projet ⇒ Propriétés ⇒ C/C++ Général ⇒ Chemins et symboles ⇒ Sous les onglets « Includes », « Chemins de bibliothèque » et « Bibliothèques ». Les paramètres sont applicables uniquement au projet sélectionné.

Variables d’environnement GCC

GCC utilise les variables d’environnement suivantes :

  • PATH : Pour la recherche des exécutables et des bibliothèques partagées d’exécution (.dll.so).
  • CPATH : Pour la recherche des include-paths pour les en-têtes. Il est recherché après les chemins spécifiés dans les options -I<dir>C_INCLUDE_PATH et CPLUS_INCLUDE_PATH peuvent être utilisés pour spécifier les en-têtes C et C++ si le langage particulier a été indiqué dans le prétraitement.
  • LIBRARY_PATH : Pour rechercher les chemins des bibliothèques de liaison. Elle est recherchée après les chemins spécifiés dans les options –L<dir>.

Utilités pour examiner les fichiers compilés

Pour tous les utilitaires GNU, vous pouvez utiliser « command --help » pour lister le menu d’aide ; ou « man command » pour afficher les pages de manuel.

Utilitaire « fichier » – Déterminer le type de fichier

L’utilitaire « file » peut être utilisé pour afficher le type de fichiers objets et de fichiers exécutables. Par exemple,

$ gcc -c hello.c$ gcc -o hello.exe hello.o $ file hello.c
hello.c: C source, ASCII text, with CRLF line terminators$ file hello.ohello.o: data > file hello.exehello.exe: PE32 executable (console) x86-64, for MS Windows
Utilitaire « nm » – Lister la table des symboles des fichiers objets

L’utilitaire « nm » liste la table des symboles des fichiers objets. Par exemple,

$ nm hello.o0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 p .pdata
0000000000000000 r .rdata
0000000000000000 r .rdata$zzz
0000000000000000 t .text
0000000000000000 r .xdata
U __main
0000000000000000 T main
U puts$ nm hello.exe | grep main
00000001004080cc I __imp___main
0000000100401120 T __main
00000001004010e0 T main
......

« nm » est couramment utilisé pour vérifier si une fonction particulière est définie dans un fichier objet. Un 'T' dans la deuxième colonne indique une fonction qui est définie, tandis qu’un 'U' indique une fonction qui est indéfinie et qui doit être résolue par l’éditeur de liens.

Utilitaire « ldd » – Lister les bibliothèques de liaison dynamique

L’utilitaire « ldd » examine un exécutable et affiche une liste des bibliothèques partagées dont il a besoin. Par exemple,

> ldd hello.exentdll.dll => /cygdrive/c/WINDOWS/SYSTEM32/ntdll.dll (0x7ff9ba3c0000)
KERNEL32.DLL => /cygdrive/c/WINDOWS/System32/KERNEL32.DLL (0x7ff9b9880000)
KERNELBASE.dll => /cygdrive/c/WINDOWS/System32/KERNELBASE.dll (0x7ff9b6a60000)
SYSFER.DLL => /cygdrive/c/WINDOWS/System32/SYSFER.DLL (0x6ec90000)
ADVAPI32.dll => /cygdrive/c/WINDOWS/System32/ADVAPI32.dll (0x7ff9b79a0000)
msvcrt.dll => /cygdrive/c/WINDOWS/System32/msvcrt.dll (0x7ff9b9100000)
sechost.dll => /cygdrive/c/WINDOWS/System32/sechost.dll (0x7ff9b9000000)
RPCRT4.dll => /cygdrive/c/WINDOWS/System32/RPCRT4.dll (0x7ff9b9700000)
cygwin1.dll => /usr/bin/cygwin1.dll (0x180040000)

GNU Make

L’utilitaire « make » automatise les aspects banals de la construction d’un exécutable à partir du code source. « make » utilise ce qu’on appelle une makefile, qui contient des règles sur la façon de construire les exécutables.

Vous pouvez émettre « make --help » pour lister les options de la ligne de commande ; ou « man make » pour afficher les pages de manuel.

Premier Makefile par exemple

Débutons par un exemple simple pour construire le programme Hello-world (hello.c) en exécutable (hello.exe) via l’utilitaire make.

1234567
// hello.c#include <stdio.h> int main() { printf("Hello, world!\n"); return 0;}

Créer le fichier suivant nommé « makefile » (sans extension de fichier), qui contient les règles pour construire l’exécutable, et enregistrez-le dans le même répertoire que le fichier source. Utilisez « tab » pour indenter la commande (PAS d’espaces).

all: hello.exehello.exe: hello.o gcc -o hello.exe hello.ohello.o: hello.c gcc -c hello.c clean: rm hello.o hello.exe

Exécutez l’utilitaire « make » comme suit :

> makegcc -c hello.cgcc -o hello.exe hello.o

L’exécution de make sans argument lance la cible « all » dans le makefile. Un makefile est constitué d’un ensemble de règles. Une règle se compose de 3 parties : une cible, une liste de pré-requis et une commande, comme suit :

target: pre-req-1 pre-req-2 ...command

La cible et les pré-requis sont séparés par un deux-points (:). La commande doit être précédée d’une tabulation (PAS d’espaces).

Lorsqu’on demande à make d’évaluer une règle, elle commence par trouver les fichiers dans les prérequis. Si l’un des prérequis a une règle associée, faire des tentatives pour mettre à jour ceux-ci en premier.

Dans l’exemple ci-dessus, la règle « all » a un prérequis « hello.exemake ne trouve pas le fichier « hello.exe« , il cherche donc une règle pour le créer. La règle « hello.exe » a un prérequis « hello.o« . Là encore, il n’existe pas, donc make cherche une règle pour le créer. La règle « hello.o » a un prérequis « hello.cmake vérifie que « hello.c » existe et qu’il est plus récent que la cible (qui n’existe pas). Elle exécute la commande « gcc -c hello.c« . La règle « hello.exe » exécute ensuite sa commande « gcc -o hello.exe hello.o« . Enfin, la règle « all » ne fait rien.

Plus important encore, si le prérequis n’est pas plus récent que la cible, la commande ne sera pas exécutée. En d’autres termes, la commande ne sera exécutée que si la cible est dépassée par rapport à son prérequis. Par exemple, si nous exécutons à nouveau la commande make :

> makemake: Nothing to be done for `all'.

Vous pouvez également spécifier la cible à réaliser dans la commande make. Par exemple, la cible « clean » supprime les « hello.o » et « hello.exe« . Vous pouvez alors exécuter le make sans cible, ce qui revient au même que « make all« .

> make cleanrm hello.o hello.exe > makegcc -c hello.cgcc -o hello.exe hello.o

Essayez de modifier le « hello.c » et exécutez make.

NOTES:

  • Si la commande n’est pas précédée d’une tabulation, vous obtenez un message d’erreur « makefile:4 : *** séparateur manquant. Stop. »
  • Si il n’y a pas de makefile dans le répertoire courant, vous obtenez un message d’erreur « make : *** Aucune cible spécifiée et aucun makefile trouvé. Stop. »
  • Le makefile peut être nommé « makefileMakefile » ou « GNUMakefile« , sans extension de fichier.

Plus sur Makefile

Comment & Continuation

Un commentaire commence par un # et dure jusqu’à la fin de la ligne. Une longue ligne peut être interrompue et continuée en plusieurs lignes via un back-slash (\).

Syntaxe des règles

Une syntaxe générale pour les règles est:

target1 : 

Les règles sont généralement organisées de telle sorte que les règles plus générales viennent en premier. La règle générale est souvent nommée « all« , qui est la cible par défaut de make.

Les cibles fictives (ou cibles artificielles)

Une cible qui ne représente pas un fichier est appelée une cible fictive. Par exemple, le « clean » dans l’exemple ci-dessus, qui n’est qu’une étiquette pour une commande. Si la cible est un fichier, elle sera vérifiée par rapport à son prérequis pour savoir si elle est périmée. Une cible fictive est toujours périmée et sa commande sera exécutée. Les cibles fictives standard sont : allcleaninstall.

Variables

Une variable commence par un $ et est placée entre parenthèses (...) ou entre accolades {...}. Les variables à caractère unique n’ont pas besoin des parenthèses. Par exemple, $(CC)$(CC_FLAGS)$@$^.

Variables automatiques

Les variables automatiques sont définies par make après la correspondance d’une règle. Elles comprennent :

  • $@ : le nom de fichier cible.
  • $* : le nom de fichier cible sans l’extension de fichier.
  • $< : le premier nom de fichier prérequis.
  • $^ : les noms de fichiers de tous les prérequis, séparés par des espaces, élimine les doublons.
  • $+ : similaire à $^, mais inclut les doublons.
  • $? : les noms de tous les prérequis qui sont plus récents que la cible, séparés par des espaces.

Par exemple, nous pouvons réécrire le makefile précédent comme :

all: hello.exe # $@ matches the target; $< matches the first dependenthello.exe: hello.ogcc -o $@ $<hello.o: hello.cgcc -c $< clean:rm hello.o hello.exe
Virtual Path – VPATH & vpath

Vous pouvez utiliser VPATH (majuscule) pour spécifier le répertoire dans lequel rechercher les dépendances et les fichiers cibles. Par exemple,

# Search for dependencies and targets from "src" and "include" directories# The directories are separated by spaceVPATH = src include

Vous pouvez également utiliser vpath (en minuscules) pour être plus précis sur le type de fichier et son répertoire de recherche. Par exemple,

# Search for .c files in "src" directory; .h files in "include" directory# The pattern matching character '%' matches filename without the extensionvpath %.c srcvpath %.h include
Règles de motif

Une règle de motif, qui utilise le caractère de correspondance de motif '%' comme nom de fichier, peut être appliquée pour créer une cible, s’il n’y a pas de règle explicite. Par exemple,

# Applicable for create .o object file.# '%' matches filename.# $< is the first pre-requisite# $(COMPILE.c) consists of compiler name and compiler options# $(OUTPUT_OPTIONS) could be -o $@%.o: %.c$(COMPILE.c) $(OUTPUT_OPTION) $< # Applicable for create executable (without extension) from object .o object file# $^ matches all the pre-requisites (no duplicates)%: %.o$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
Règles de motifs implicites

Make est livré avec un énorme ensemble de règles de motifs implicites. Vous pouvez lister toutes les règles via --print-data-base option.

Un exemple de Makefile

Cet exemple de makefile est extrait du « Guide de développement C/C++ -Makefile » d’Eclipse.

# A sample Makefile# This Makefile demonstrates and explains # Make Macros, Macro Expansions,# Rules, Targets, Dependencies, Commands, Goals# Artificial Targets, Pattern Rule, Dependency Rule.# Comments start with a # and go to the end of the line.# Here is a simple Make Macro.LINK_TARGET = test_me.exe# Here is a Make Macro that uses the backslash to extend to multiple lines.OBJS = \ Test1.o \ Test2.o \ Main.o# Here is a Make Macro defined by two Macro Expansions.# A Macro Expansion may be treated as a textual replacement of the Make Macro.# Macro Expansions are introduced with $ and enclosed in (parentheses).REBUILDABLES = $(OBJS) $(LINK_TARGET)# Here is a simple Rule (used for "cleaning" your build environment).# It has a Target named "clean" (left of the colon ":" on the first line),# no Dependencies (right of the colon),# and two Commands (indented by tabs on the lines that follow).# The space before the colon is not required but added here for clarity.clean : rm -f $(REBUILDABLES) echo Clean done# There are two standard Targets your Makefile should probably have:# "all" and "clean", because they are often command-line Goals.# Also, these are both typically Artificial Targets, because they don't typically# correspond to real files named "all" or "clean". # The rule for "all" is used to incrementally build your system.# It does this by expressing a dependency on the results of that system,# which in turn have their own rules and dependencies.all : $(LINK_TARGET) echo All done# There is no required order to the list of rules as they appear in the Makefile.# Make will build its own dependency tree and only execute each rule only once# its dependencies' rules have been executed successfully.# Here is a Rule that uses some built-in Make Macros in its command:# $@ expands to the rule's target, in this case "test_me.exe".# $^ expands to the rule's dependencies, in this case the three files# main.o, test1.o, and test2.o.$(LINK_TARGET) : $(OBJS) g++ -g -o $@ $^# Here is a Pattern Rule, often used for compile-line.# It says how to create a file with a .o suffix, given a file with a .cpp suffix.# The rule's command uses some built-in Make Macros:# $@ for the pattern-matched target# $< for the pattern-matched dependency%.o : %.cpp g++ -g -o $@ -c $<# These are Dependency Rules, which are rules without any command.# Dependency Rules indicate that if any file to the right of the colon changes,# the target to the left of the colon should be considered out-of-date.# The commands for making an out-of-date target up-to-date may be found elsewhere# (in this case, by the Pattern Rule above).# Dependency Rules are often used to capture header file dependencies.Main.o : Main.h Test1.h Test2.hTest1.o : Test1.h Test2.hTest2.o : Test2.h# Alternatively to manually capturing dependencies, several automated# dependency generators exist. Here is one possibility (commented out)...# %.dep : %.cpp# g++ -M $(FLAGS) $< > $@# include $(OBJS:.o=.dep)

Brief Summary

J’ai présenté ici les fonctionnalités de base de make afin que vous puissiez lire et comprendre des makefiles simples pour construire des applications C/C++. Make est en réalité assez complexe, et peut être considéré comme un langage de programmation à lui seul !

.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *