Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Les principales options de gcc

Les nouveautés introduites par C11


Accès rapide :
Rappels sur le processus de construction d'un programme C.
Options d'arrêt au terme d'une étape du cycle de construction d'un programme
Arrêt après la phase du pré-processeur.
Arrêt après l'étape de génération du code assembleur
Arrêt après la phase d'assemblage
Lancement de la phase d'édition des liens
Récapitulatif
Options relatives à la gestion des warnings
Compiler en mode « Debug »
Options relatives à des demandes d'optimisations
Obtention de l'aide

Rappels sur le processus de construction d'un programme C.

Le processus de construction d'un programme C (on parle aussi de processus de build), passe par plusieurs étapes : le préprocesseur, la compilation et la phase d'édition des liens.

Le processus de construction d'un programme C

L'étape de compilation peut elle-même être découpée en sous-parties : le contrôle du typage, la génération du code assembleur, puis celle du code machine.

Via diverses options, vous pouvez demander à gcc de s'arrêter au terme de n'importe quelle étape du processus de build.

Options d'arrêt au terme d'une étape du cycle de construction d'un programme

Considérons le programme C suivant : il va nous servir à tester certaines des options proposées.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
#include <stdio.h>
#include <stdlib.h>

#define a 10
#define b 20
#define min(x,y) ( (x)<(y) ? (x) : (y) )

int main() {

    int result = min( a, b ) + 2;
    printf( "Hello World with %d\n", result );

    return EXIT_SUCCESS;
}
Un programme relativement simpliste

Arrêt après la phase du pré-processeur.

Pour demander un arrêt de gcc après la phase de pré-processeur, il faut utiliser l'option -E.

$> gcc -E essai.c 1> temp.c
le pré-processeur ne génère pas de fichier physique sur le disque dur : vous pouvez obtenir en obtenir un, mais cela reste de votre responsabilité. D'où l'utilisation de l'opérateur de redirection de flux 1> temp.c.

Le fichier produit étant très conséquent (tous les fichiers inclus via la directive #include ont été injectés dans le fichier final), je me permets de vous en afficher que les dernières lignes.

$> cat temp.c
... Début du fichier produit ...

# 8 "essai.c"
int main() {

    int result = ( (10)<(20) ? (10) : (20) ) + 2;
    printf( "Hello World with %d\n", result );

    return 
# 13 "essai.c" 3 4
          0
# 13 "essai.c"
                      ;
}
vous devriez y remarquer le remplacement des macros par le code résultant (y compris la macro EXIT_SUCCESS).

Arrêt après l'étape de génération du code assembleur

Les plus curieux d'entre vous pourraient jeter un coup d'oeil sur le code assembleur produit. Pour ce faire, il faut utiliser l'option -S. Naturellement, le code ne sera pas assemblé pour produire le code machine.

$> gcc -S essai.c -o essai.ass

Et voici le contenu du fichier de code assembleur ainsi produit.

$> cat essai.asscat essai.ass
    .file   "essai.c"
    .text
    .section    .rodata
.LC0:
    .string "Hello World with %d\n"
    .text
    .globl  main
    .type   main, @function
main:
.LFB6:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    $12, -4(%rbp)
    movl    -4(%rbp), %eax
    movl    %eax, %esi
    movl    $.LC0, %edi
    movl    $0, %eax
    call    printf
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE6:
    .size   main, .-main
    .ident  "GCC: (GNU) 9.2.1 20190827 (Red Hat 9.2.1-1)"
    .section    .note.GNU-stack,"",@progbits
$> 

Arrêt après la phase d'assemblage

C'est une étape que, normalement, vous connaissez bien : il suffit d'ajouter l'option -c pour s'arrêter à ce niveau. On se situe juste avant la phase d'édition des liens. Un fichier d'extension .o (pour objet) sera produit.

$> gcc -c essai.c
$> ls
essai.c  essai.o
$> 

Lancement de la phase d'édition des liens

Pour lancer la dernière phase du « build » de votre programme, il ne faut pas mettre d'option d'arrêt du processus de construction. (-E, -S, -c, ...). Il faut alors utiliser l'option -o si vous souhaitez contrôler le nom du fichier finalement produit. On peut envisager deux cas classiques.

Au terme de cette étape, vous avez normalement produit un exécutable.

$> ls -l
-rwxrwxr-x. 1 dominique dominique 21976 27 nov.  16:42 essai
-rw-rw-r--. 1 dominique dominique   231 27 nov.  16:42 essai.c
-rw-rw-r--. 1 dominique dominique  1528 27 nov.  16:43 essai.o
$> ./essai
Hello World with 12
$> 

Récapitulatif

-E : permet de stopper le processus de construction après la phase du pré-processeur.

-S : permet de stopper le processus de construction après l'étape de production du code assembleur.

-c : permet de stopper le processus de construction après la phase de compilation (ie, production du code assembleur, puis du code machine).

-o : permet de spécifier le nom du fichier produit, quelle que soit sa nature (code assembleur, code machine ou exécutable).

Options relatives à la gestion des warnings

-Wall : affiche tous les types de warnings. Par exemple, avec cette option, les variables déclarées mais non utilisées produiront des warnings.

-Wconversion : affiche des warnings en cas de cast implicit et de perte de précision. Je vous recommande l'emploi systématique de cette option. Attention, elle ne fait pas partie du périmètre de l'option -Wall.

-Werror : demande au compilateur de traiter les warnings affichés en tant qu'erreurs. D'un certain point de vue, on peut juger cette possibilité comme étant très contraignante, mais d'un autre point de vue, cette option permet de mieux maîtriser la qualité des codes produits. Je vous recommande aussi l'emploi systématique de cette option.

Compiler en mode « Debug »

-g : pour compiler votre programme en mode « Debug » et ainsi pouvoir y faire du pas à pas (via gdb, pourquoi pas).

Options relatives à des demandes d'optimisations

Par défaut le compilateur ne cherche pas à jouer toutes les optimisations possibles. Si vous souhaitez contrôler l'optimisation de votre programme, il faudra utiliser l'une des options suivantes.

-O0 : aucune optimisation demandée.

-O1 : un premier niveau d'optimisation qui conserve une taille de l'exécutable minimale.

-O2 : un niveau d'optimisation intermédiaire avec un bon compromis sur la taille du fichier.

-O3 : toutes les optimisations sont demandées, quelles qu'en soient les conséquences sur la taille de l'exécutable.

Obtention de l'aide

Pour clore ce chapitre, notez que vous pouvez aussi obtenir de l'aide à propos de l'utilisation de votre compilateur gcc. La manière la plus simple consiste à lancer la commande gcc avec l'option --help : une aide succincte devrait apparaître.

$> gcc --help 
Usage : gcc [options] fichier...
Options :
  -pass-exit-codes         Quitter avec le plus grand code d'erreur d'une phase.
  --help                   Afficher cette aide.
  --target-help            Afficher les options de ligne de commande spécifiques à la cible.
 --help={common|optimizers|params|target|warnings|[^]{joined|separate|undocumented}}[,...].
                           Afficher les types spécifiques des options de la ligne de commande.
  (Utilisez " -v --help " pour afficher les options de la ligne de commande des sous-processus).
  --version                Afficher des informations sur la version du compilateur.
  -dumpspecs               Afficher toutes les chaînes de specs internes.
  -dumpversion             Afficher la version du compilateur.
  -dumpmachine             Afficher le processeur ciblé par le compilateur.
  -print-search-dirs       Afficher les répertoires du chemin de recherche du compilateur.
  -print-libgcc-file-name  Afficher le nom de la bibliothèque accompagnant le compilateur.
  -print-file-name=<lib>   Afficher le chemin complet vers la bibliothèque <lib>.
  -print-prog-name=<prog>  Afficher le chemin complet vers le composant <prog> du compilateur.
  -print-multiarch         Afficher le triplet GNU normalisé de la cible, utilisé comme
                           un composant dans le chemin d'accès de la bibliothèque.
  -print-multi-directory   Afficher la racine du répertoire des versions de libgcc.
  -print-multi-lib         Afficher la table de correspondance entre les options de
                           la ligne de commande et les multiples répertoires de
                           recherche des bibliothèques.
  -print-multi-os-directory Afficher le chemin relatif vers les bibliothèques de l'OS.
  -print-sysroot           Afficher le répertoire des bibliothèques de la cible.
  -print-sysroot-headers-suffix Afficher le suffixe de la racine système utilisé pour trouver les en-têtes.
  -Wa,<options>            Passer les <options> séparées par des virgules à l'assembleur.
  -Wp,<options>            Passer les <options> séparées par des virgules au préprocesseur.
  -Wl,<options>            Passer les <options> séparées par des virgules à l'éditeur de liens.
  -Xassembler <argument>   Passer l'<argument> à l'assembleur.
  -Xpreprocessor <argument>Passer l'<argument> au préprocesseur.
  -Xlinker <argument>      Passer l'<argument> à l'éditeur de liens.
  -save-temps              Ne pas détruire les fichiers intermédiaires.
  -save-temps=<arg>        Ne pas effacer les fichiers intermédiaires.
  -no-canonical-prefixes   Ne pas normaliser les chemins lors de la compilation
                           de préfixes relatifs à d'autres composants de gcc.
  -pipe                    Utiliser des pipes au lieu de fichiers intermédiaires.
  -time                    Mesurer le temps d'exécution de chaque sous-processus.
  -specs=<fichier>         Remplacer les specs internes par le contenu du <fichier>.
  -std=<standard>          Supposer que les fichiers sources respectent le <standard>.
  --sysroot=<répertoire>   Utiliser <répertoire> comme répertoire racine pour les
                           en-têtes et les bibliothèques.
  -B <répertoire>          Ajouter le <répertoire> aux chemins de recherche du compilateur.
  -v                       Afficher les programmes invoqués par le compilateur.
  -###                     Identique à -v mais les options et les commandes entre guillemets ne sont pas exécutées.
  -E                       Pré-traitement seul ; ne pas compiler, assembler ou éditer les liens.
  -S                       Compilation seule ; ne pas assembler ou éditer les liens.
  -c                       Compiler et assembler, mais ne pas éditer les liens.
  -o <fichier>             Placer la sortie dans le <fichier>.
  -pie                     Créer un exécutable indépendant de la position en
                           mémoire (PIE) lié dynamiquement.
  -shared                  Créer une bibliothèque partagée.
  -x <langage>             Spécifier le langage des fichiers d'entrée suivants.
                           Les langages permis sont: c c++ assembler none
                           "none" signifiant d'utiliser le comportement par défaut
                           en tentant d'identifier le langage par l'extension du fichier.

Options débutant par -g, -f, -m, -O, -W, ou --param sont automatiquement
 passées aux divers sous-processus invoqués par gcc.  Afin de passer
 les autres options à ces processus l'option -W<lettre> doit être utilisé.

Pour les instructions afin de rapporter des anomalies, consultez :
<http://bugzilla.redhat.com/bugzilla>.

Pour obtenir une aide bien plus détaillée, lancez la commande man sur le compilateur gcc.

$> man gcc




Les nouveautés introduites par C11