2.2. Construire un code avec GCC
Ce chapitre décrit les situations dans lesquelles le code source doit être transformé en code exécutable.
2.2.1. Relation entre les formes de code
Conditions préalables
- Comprendre les concepts de compilation et de liaison
Formes de code possibles
Les langages C et C ont trois formes de code :
Source code écrites en langage C ou C, présentées sous forme de fichiers de texte brut.
Les fichiers utilisent généralement des extensions telles que
.c
,.cc
,.cpp
,.h
,.hpp
,.i
,.inc
. Pour une liste complète des extensions supportées et de leur interprétation, voir les pages de manuel de gcc :$ man gcc
Object code compiling compileril s'agit d'une forme intermédiaire.
Les fichiers de code objet utilisent l'extension
.o
.Executable code, créé par le code objet linking avec un code objet linker.
Les fichiers exécutables des applications Linux n'utilisent aucune extension de nom de fichier. Les fichiers exécutables d'objets partagés (bibliothèques) utilisent l'extension de nom de fichier
.so
.
Il existe également des fichiers d'archives de bibliothèques pour l'établissement de liens statiques. Il s'agit d'une variante du code objet qui utilise l'extension de nom de fichier .a
. La liaison statique n'est pas recommandée. Voir Section 2.3.2, « Liaison statique et dynamique ».
Traitement des formes de code dans GCC
La production d'un code exécutable à partir d'un code source s'effectue en deux étapes, qui nécessitent des applications ou des outils différents. GCC peut être utilisé comme pilote intelligent pour les compilateurs et les éditeurs de liens. Cela vous permet d'utiliser une seule commande gcc
pour n'importe laquelle des actions requises (compilation et liaison). GCC sélectionne automatiquement les actions et leur ordre :
- Les fichiers sources sont compilés en fichiers objets.
- Les fichiers objets et les bibliothèques sont liés (y compris les sources compilées précédemment).
Il est possible d'exécuter GCC de manière à ce qu'il effectue uniquement la compilation, uniquement l'édition de liens, ou à la fois la compilation et l'édition de liens en une seule étape. Ceci est déterminé par les types d'entrées et le type de sortie(s) demandé(s).
Comme les grands projets nécessitent un système de compilation qui exécute généralement GCC séparément pour chaque action, il est préférable de toujours considérer la compilation et l'édition de liens comme deux actions distinctes, même si GCC peut exécuter les deux en même temps.
2.2.2. Compilation des fichiers source en code objet
Pour créer des fichiers de code objet à partir de fichiers source et non un fichier exécutable immédiatement, il faut demander à GCC de ne créer que des fichiers de code objet en sortie. Cette action représente l'opération de base du processus de construction pour les grands projets.
Conditions préalables
- Fichier(s) de code source C ou C
- GCC installé sur le système
Procédure
- Se rendre dans le répertoire contenant le(s) fichier(s) du code source.
Exécutez
gcc
avec l'option-c
:$ gcc -c source.c another_source.c
Des fichiers objets sont créés, dont les noms reflètent les fichiers du code source original :
source.c
donne lieu àsource.o
.NoteAvec le code source C, remplacez la commande
gcc
parg
pour une gestion pratique des dépendances de la bibliothèque standard C.
2.2.3. Débogage des applications C et C avec GCC
Les informations de débogage étant volumineuses, elles ne sont pas incluses par défaut dans les fichiers exécutables. Pour permettre le débogage de vos applications C et C avec elle, vous devez explicitement demander au compilateur de la créer.
Pour permettre la création d'informations de débogage avec GCC lors de la compilation et de l'édition de liens, utilisez l'option -g
:
$ gcc ... -g ...
-
Les optimisations effectuées par le compilateur et l'éditeur de liens peuvent aboutir à un code exécutable difficile à relier au code source original : les variables peuvent être optimisées, les boucles déroulées, les opérations fusionnées avec les opérations environnantes, etc. Cela a un impact négatif sur le débogage. Pour améliorer l'expérience de débogage, envisagez de définir l'optimisation avec l'option
-Og
. Cependant, la modification du niveau d'optimisation modifie le code exécutable et peut changer le comportement réel, y compris la suppression de certains bogues. -
Pour inclure également les définitions de macros dans les informations de débogage, utilisez l'option
-g3
au lieu de-g
. -
L'option
-fcompare-debug
GCC teste le code compilé par GCC avec des informations de débogage et sans informations de débogage. Le test est réussi si les deux fichiers binaires résultants sont identiques. Ce test garantit que le code exécutable n'est pas affecté par les options de débogage, ce qui permet de s'assurer qu'il n'y a pas de bogues cachés dans le code de débogage. Notez que l'utilisation de l'option-fcompare-debug
augmente de manière significative le temps de compilation. Voir la page de manuel de GCC pour plus de détails sur cette option.
Ressources supplémentaires
- Utilisation de la collection de compilateurs GNU (GCC) - Options pour déboguer votre programme
- Débogage avec GDB - Informations de débogage dans des fichiers séparés
La page du manuel GCC :
$ man gcc
2.2.4. Optimisation du code avec GCC
Un même programme peut être transformé en plusieurs séquences d'instructions machine. Vous pouvez obtenir un résultat plus optimal si vous allouez plus de ressources à l'analyse du code lors de la compilation.
Avec GCC, vous pouvez définir le niveau d'optimisation en utilisant l'option -Olevel
pour définir le niveau d'optimisation. Cette option accepte un ensemble de valeurs à la place de level.
Level | Description |
---|---|
| Optimiser la vitesse de compilation - pas d'optimisation du code (par défaut). |
| Optimiser pour augmenter la vitesse d'exécution du code (plus le nombre est élevé, plus la vitesse est grande). |
| Optimiser la taille du fichier. |
|
Identique à un réglage de niveau |
| Optimiser l'expérience de débogage. |
Pour les versions, utilisez l'option d'optimisation -O2
.
Pendant le développement, l'option -Og
est utile pour déboguer le programme ou la bibliothèque dans certaines situations. Comme certains bogues ne se manifestent qu'avec certains niveaux d'optimisation, testez le programme ou la bibliothèque avec le niveau d'optimisation de la version.
GCC offre un grand nombre d'options pour permettre des optimisations individuelles. Pour plus d'informations, voir les ressources supplémentaires suivantes.
Ressources supplémentaires
- Utilisation de la collection de compilateurs GNU - Options qui contrôlent l'optimisation
Page de manuel Linux pour GCC :
$ man gcc
2.2.5. Options de durcissement du code avec GCC
Lorsque le compilateur transforme le code source en code objet, il peut ajouter diverses vérifications afin d'éviter les situations couramment exploitées et d'accroître la sécurité. Le choix du bon ensemble d'options du compilateur peut aider à produire des programmes et des bibliothèques plus sûrs, sans avoir à modifier le code source.
Options de version
La liste d'options suivante est le minimum recommandé pour les développeurs ciblant Red Hat Enterprise Linux :
$ gcc ... -O2 -g -Wall -Wl,-z,now,-z,relro -fstack-protector-strong -fstack-clash-protection -D_FORTIFY_SOURCE=2 ...
-
Pour les programmes, ajoutez les options
-fPIE
et-pie
Position Independent Executable. -
Pour les bibliothèques liées dynamiquement, l'option obligatoire
-fPIC
(Position Independent Code) augmente indirectement la sécurité.
Options de développement
Utilisez les options suivantes pour détecter les failles de sécurité pendant le développement. Utilisez ces options en conjonction avec les options de la version release :
$ gcc ... -Walloc-zero -Walloca-larger-than -Wextra -Wformat-security -Wvla-larger-than ...
Ressources supplémentaires
- Guide de codage défensif
- Détection d'erreurs de mémoire à l'aide de GCC - Red Hat Developers Blog post
2.2.6. Lier le code pour créer des fichiers exécutables
L'édition de liens est la dernière étape de la construction d'une application C ou C. L'édition de liens combine tous les fichiers objets et les bibliothèques en un fichier exécutable.
Conditions préalables
- Un ou plusieurs fichier(s) objet(s)
- GCC doit être installé sur le système
Procédure
- Se rendre dans le répertoire contenant le(s) fichier(s) de code objet.
Exécuter
gcc
:$ gcc ... objfile.o another_object.o... -o executable-file
Un fichier exécutable nommé executable-file est créé à partir des fichiers objets et des bibliothèques fournis.
Pour lier des bibliothèques supplémentaires, ajoutez les options requises après la liste des fichiers objets.
NoteAvec le code source C, remplacez la commande
gcc
parg
pour une gestion pratique des dépendances de la bibliothèque standard C.
2.2.7. Exemple : Construction d'un programme C avec GCC (compilation et liaison en une seule étape)
Cet exemple montre les étapes exactes de la construction d'un programme C simple.
Dans cet exemple, la compilation et l'enchaînement du code se font en une seule étape.
Conditions préalables
- Vous devez savoir comment utiliser GCC.
Procédure
Créez un répertoire
hello-c
et accédez-y :$ mkdir hello-c $ cd hello-c
Créez le fichier
hello.c
avec le contenu suivant :#include <stdio.h> int main() { printf("Hello, World!\n"); return 0; }
Compiler et lier le code avec GCC :
$ gcc hello.c -o helloworld
Cette opération compile le code, crée le fichier objet
hello.o
et lie le fichier exécutablehelloworld
à partir du fichier objet.Exécutez le fichier exécutable obtenu :
$ ./helloworld Hello, World!
2.2.8. Exemple : Construction d'un programme C avec GCC (compilation et liaison en deux étapes)
Cet exemple montre les étapes exactes de la construction d'un programme C simple.
Dans cet exemple, la compilation et l'enchaînement du code sont deux étapes distinctes.
Conditions préalables
- Vous devez savoir comment utiliser GCC.
Procédure
Créez un répertoire
hello-c
et accédez-y :$ mkdir hello-c $ cd hello-c
Créez le fichier
hello.c
avec le contenu suivant :#include <stdio.h> int main() { printf("Hello, World!\n"); return 0; }
Compilez le code avec GCC :
$ gcc -c hello.c
Le fichier objet
hello.o
est créé.Lier un fichier exécutable
helloworld
à partir du fichier objet :$ gcc hello.o -o helloworld
Exécutez le fichier exécutable obtenu :
$ ./helloworld Hello, World!
2.2.9. Exemple : Construction d'un programme C avec GCC (compilation et liaison en une seule étape)
Cet exemple montre les étapes exactes de la construction d'un exemple de programme C minimal.
Dans cet exemple, la compilation et l'enchaînement du code se font en une seule étape.
Conditions préalables
-
Vous devez comprendre la différence entre
gcc
etg
.
Procédure
Créez un répertoire
hello-cpp
et accédez-y :$ mkdir hello-cpp $ cd hello-cpp
Créez le fichier
hello.cpp
avec le contenu suivant :#include <iostream> int main() { std::cout << "Hello, World!\n"; return 0; }
Compiler et lier le code avec
g
:$ g++ hello.cpp -o helloworld
Cette opération compile le code, crée le fichier objet
hello.o
et lie le fichier exécutablehelloworld
à partir du fichier objet.Exécutez le fichier exécutable obtenu :
$ ./helloworld Hello, World!
2.2.10. Exemple : Construction d'un programme C avec GCC (compilation et liaison en deux étapes)
Cet exemple montre les étapes exactes de la construction d'un exemple de programme C minimal.
Dans cet exemple, la compilation et l'enchaînement du code sont deux étapes distinctes.
Conditions préalables
-
Vous devez comprendre la différence entre
gcc
etg
.
Procédure
Créez un répertoire
hello-cpp
et accédez-y :$ mkdir hello-cpp $ cd hello-cpp
Créez le fichier
hello.cpp
avec le contenu suivant :#include <iostream> int main() { std::cout << "Hello, World!\n"; return 0; }
Compilez le code avec
g
:$ g++ -c hello.cpp
Le fichier objet
hello.o
est créé.Lier un fichier exécutable
helloworld
à partir du fichier objet :$ g++ hello.o -o helloworld
Exécutez le fichier exécutable obtenu :
$ ./helloworld Hello, World!