Initialement appelé Gnu C Compiler, il a été renommé Gnu Compiler Collection puisqu'il permet de compiler divers langages tels que:
Gnu Compiler Collection est l'outil généraliste de compilation du projet GNU. Il s'articule autour de plusieurs outils:
La commande gcc est une interface permettant d'appeler de façon unifiée les différentes étapes de compilation.
Le compilateur gcc de GNU passe par les étapes suivante pour compiler un fichier C:
Dans le fichier source, une ligne commençant par # n'est pas du C mais une directive pour le préprocesseur. Les directives telles que #define permettent d'augmenter la lisibilité et la maintenabilité du code. Le préprocesseur, appelé cpp (C PreProcessor) traite le fichier source en remplace les directives #includes, les commentaires etc. Le fichier obtenu en sortie est un fichier source contenant exclusivement des instructions C.
Le travail du préprocesseur peut être révélé avec l'argument -E de gcc:
/* ######################################### # hello.c # # Mon premier programme C # ######################################### */ #include <stdio.h> #define carre(a) ((a)*(a)) int main(void) { printf("hello big world!\n"); int nb=8; printf("nb=%d et %d est son carre.\n", nb, carre(nb) ); return 0; }
gcc -E hello.c
# 1 "hello.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "hello.c" ... typedef struct { int __count; union { unsigned int __wch; char __wchb[4]; } __value; } __mbstate_t; ... ... ... int main(void) { printf("hello big world!\n"); int nb=8; printf("nb=%d et %d est son carre.\n", nb, ((nb)*(nb)) ); return 0; }
Pour info, les commandes ci-dessous permettent de comparer les fichiers:
cat hello.c | wc -l 17 gcc -E hello.c | wc -l 851
Notre fichier source hello.c passe de 17 lignes a 851 après traitement du préprocesseur.
Pour demander à gcc de compiler un fichier source la syntaxe est la suivante:
gcc -c monfichier.c -o monfichier.o
(gcc génère un fichier assembleur (phase assemblage) puis un fichier objet. On peut demander à gcc de stopper la compilation a la phase de traduction en langage assembleur pour voir le code assembleur produit:
gcc -S hello.c
Et traduire ensuite le code assembleur en code machine
as hello.c -o hello.o
Une fois les fichiers objets créés, il faut les fusionner correctement pour créer le fichier exécutable (j’évite ici le terme assembler): c'est la phase d'édition des liens faite par le linker. la commande permettant d'invoquer le linker:
gcc monfichier.o -o monfichier
Sous Linux la plupart des exécutables sont liés dynamiquement, c'est à dire qu'ils n'incluent pas directement le code des fonctions utilisées. Lors de la phase d’édition de liens un code spécifique est ajouté, il est capable d’appeler du code en dehors de l’exécutable.
Pour voir à quelles bibliothèques un exécutable est lié, utiliser la commande ldd
$ ldd hello.exe linux-gate.so.1 => (0x00915000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00bc4000) /lib/ld-linux.so.2 (0x009b9000)
On peut faire le choix d'utiliser à la place de la liaison dynamique la liaison statique. Lors de la phase d'édition des liens on utilise l'argument -static:
$ gcc -static monficheir.o -o monfichier
On obtient un binaire moins modulaire mais qui inclus le code dont il a besoin. S'il repose sur des bibliothèques qui ont été mises à jour, il faudra recompiler le programme pour qu'il intègre les modifications.
Lors de l'édition des liens, des fichiers objets présents dans des bibliothèques peuvent être spécifiés. Si la bibliothèque n'est pas dans un dossier standard il faut préciser au linker le dossier dans lequel elle est présente ainsi que son nom, c'est que permettent de faire les options -L (--library-path=) et -l (--library=) :
gcc -L ~/repertoire -lmalib monfichier.o -o monfichier
Pour un programme se reposant sur les liaisons dynamiques (libXXX.so), il faudra impérativement indiquer dans quels répertoires sont stockées les bibliothèques. Ceci peut être fait notamment grâce à la variable d'environnement LD_LIBRARY_PATH
C'est rassembler plusieurs fichiers objets dans un seul fichier (une archive) avec ar (options ur (ajouter et remplace et v verbeux)
$ ar ruv libmalib.a module*.o ar: creating libmalib.a a - module1.o a - module2.o a - module3.o
Dans le répertoire parent on modifie hello.c pour lui faire utiliser les fonctions. On compile ensuite:
$ gcc hello.c -Llib -lm -lmalib -o hello
Pour créer une bibliothèque dynamique, utiliser l'option -shared
$ gcc -shared module*.o -o libmalib.so
Le fichier libmalib.so est créé, il peut être ensuite liée dynamiquement à l’exécutable hello:
$ gcc hello.o -L./lib -lmalib -lm -o hello.dyn
Pour vérifier à quelles bibliothèques dynamiques est lié notre exécutable:
$ ldd hello.dyn linux-gate.so.1 => (0x00fc1000) libmalib.so => not found libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x00698000) libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00cb4000) /lib/ld-linux.so.2 (0x004f8000)
$ ./hello.dyn ./hello.dyn: error while loading shared libraries: libmalib.so: cannot open shared object file: No such file or directory