{{tag>dev c compilation gcc}} ====== GCC ====== Initialement appelé Gnu C Compiler, il a été renommé Gnu Compiler Collection puisqu'il permet de compiler divers langages tels que: * C/C++ * Objective C * Ada * Java * VHDL * etc Gnu Compiler Collection est l'outil généraliste de compilation du projet GNU. Il s'articule autour de plusieurs outils: * Le frontend gcc qui a pour but d'analyser et de traduire les fichiers sources en code assembleur correspondant à la cible. * Le backend constitué par les bin-utils assemble et lie aux bibliothèques les fichiers objets pour produire les fichiers exécutables. La commande gcc est une interface permettant d'appeler de façon unifiée les différentes étapes de compilation. ===== Étapes de compilation ===== Le compilateur gcc de GNU passe par les étapes suivante pour compiler un fichier C: - préprocesseur, - compilation, - liaison. ==== préprocesseur ==== 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 #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 "" # 1 "" # 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. ==== compilateur ==== 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 ==== linker ==== 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. ===== Bibliothèques, liaison statique / dynamique ===== 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 A propos de la nomenclature du paramètre suivant l'option **-l**: s'il a la forme d'un nom de fichier, le linker recherche le fichier dans les répertoires des bibliothèques, sinon il considère que la bibliothèque est nommée libxx.so **-ltoto** correspond aux fichier **libtoto.so** * libmalib.so: bibliothèque contenant des fichiers objets pour liaison dynamique (.so = shared object)). * libmalib.a: bibliothèque contenant des fichiers objets pour liaison statique. 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** ===== Créer une bibliothèque ===== ==== Pour liaison statique ==== C'est rassembler plusieurs fichiers objets dans un seul fichier (une archive) avec **ar** (options ur (ajouter et remplace et v verbeux) * On crée les fichiers lib/module1.c lib/module2.c lib/module3.c et malib.h * On compile les fichiers sources puis on crée l'archive $ 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 liaison dynamique ==== 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 ===== Références ===== * https://www.cmi.univ-mrs.fr/~contensi/coursC/index.php?section=env&page=comp