3. Compiler avec cc

Cette section ne s'occupe que du compilateur GNU pour C et C++, qui est fourni de base avec le système FreeBSD. Il peut être appelé soit avec la commande cc, soit avec gcc. Les détails de la réalisation d'un programme avec un interpréteur varient considérablement d'un interpréteur à l'autre, est sont généralement bien décrits par l'aide en ligne de l'interpréteur.

Une fois que vous avez écrit votre chef-d'oeuvre, l'étape suivante consiste à le convertir en quelque chose qui (espérons-le!) s'exécutera sous FreeBSD. Cela demande habituellement plusieurs opérations successives, dont chacune est confiée à un programme différent.

  1. Pré-processer votre code source pour en éliminer les commentaires et faire diverses autres choses, comme la substitution des macros-instructions en C.

  2. Vérifier la syntaxe de votre code pour s'assurer que vous avez respecté les règles du langage. Si ce n'est pas le cas, il rouspétera.

  3. Convertir le code source en langage assembleur - c'est très proche du code machine, mais encore compréhensible par des êtres humains. C'est du moins ce que l'on prétend[1].

  4. Convertir le langage assembleur en code machine - oui, nous parlons ici de bits et d'octets, de zéros et de uns.

  5. Vérifier que vous avez utilisé de façon cohérente les fonctions et les variables globales. Si, par exemple, vous avez appelé une fonction qui n'existe pas, il s'en plaindra.

  6. Si vous essayez de générer un programme à partir de plusieurs fichiers de source, faire ce qu'il faut pour les regrouper.

  7. S'arranger pour produire quelque chose que le chargeur de programmes du système pourra mettre en mémoire et exécuter.

Le mot compiler est souvent utilisé pour ne désigner que les étapes 1 à 4 - les autres sont appelées édition de liens. L'étape 1 est parfois appelée pré-processer et les étapes 3-4 assembler.

Heureusement, pratiquement tous ces détails vous sont transparents, car la commande cc est une interface qui gère pour vous l'appel de ces différents programmes avec les bons arguments; taper simplement:

% cc foobar.c

effectue la compilation de foobar.c en passant par toutes les étapes décrites ci-dessus. Si vous avez à compiler plus d'un fichier, faites simplement quelque chose comme:

% cc foo.c bar.c

Notez que la vérification syntaxique ne consiste qu'en cela: vérifier la syntaxe. Il n'y aura pas de contrôle sur les erreurs logiques que vous auriez commises, comme faire exécuter au programme une boucle infinie ou utiliser un tri à bulles au lieu d'un tri par arbre binaire[2].

cc dispose d'une quantité d'options, qui sont toutes décrites dans les pages de manuel. En voici quelques-unes des plus importantes, et la façon de les utiliser.

-o nom_de_fichier

Le nom du fichier résultat. Si vous n'utilisez pas cette option, cc générera un exécutable appelé a.out[3].

% cc foobar.c               l'exécutable est a.out
% cc -o foobar foobar.c     l'exécutable est foobar
-c

Uniquement compiler le fichier, ne pas faire l'édition de liens. Utile pour des programmes d'essai, quand vous voulez simplement vérifier la syntaxe, ou si vous vous servez d'un Makefile.

% cc -c foobar.c

Cela générera un fichier objet (et non un exécutable) appelé foobar.o. Il pourra être lié avec d'autres fichiers objet pour constituer un exécutable.

-g

Crée une version débogable de l'exécutable Le compilateur inclut alors dans l'exécutable des informations de correspondance entre les numéros de ligne du fichier source et les fonctions appelées. Un débogueur peut alors utiliser ces informations pour vous afficher le code source tandis que vous exécutez pas à pas le programme, ce qui est très utile; l'inconvénient est que toutes ces informations augmentent considérablement la taille du programme. Normalement, vous compilez avec -g quand vous développez le programme, et compilez ensuite une “version de livraison” quand vous êtes satisfait parce qu'il fonctionne correctement.

% cc -g foobar.c

Cela produira une version débogable du programme[4].

-O

Génère une version optimisée de l'exécutable. Le compilateur effectue alors diverses opérations bien pensées pour essayer de construire un programme qui aille plus vite que normalement. Vous pouvez faire suivre -O d'un nombre pour demander un degré plus important d'optimisation, mais cela met souvent en évidence des bogues dans l'optimiseur du compilateur. Par exemple, on sait que la version de cc de FreeBSD 2.1.0 produit du code incorrect avec l'option -O2 dans certaines circonstances.

On n'active en général l'optimisation qu'à la compilation de la version de livraison.

% cc -O -o foobar foobar.c

Cela construira une version optimisée de foobar.

Les trois indicateurs suivants demanderont à cc de vérifier que votre code est conforme à la norme internationale, souvent appelée norme ANSI, bien que ce soit à proprement parler une norme ISO.

-Wall

Active tous les messages d'avertissement que les auteurs du compilateur cc ont jugés intéressants. Malgré son nom (“all” - tous), cela n'active pas tous les messages d'avertissement dont le compilateur est capable.

-ansi

Désactive la plupart, mais pas toutes, les possibilités non-ANSI C fournies par cc. Malgré son nom, cela ne garantit pas absolument que votre code soit conforme à la norme.

-pedantic

Désactive toutes les possibilités non-ANSI C de cc.

Sans ces indicateurs, cc vous permet d'utiliser ses extensions non-standard de la norme. Quelques-unes sont très utiles, mais ne se retrouveront pas sur d'autres compilateurs - de fait, l'un des objectifs principaux de la norme est de permettre l'écriture de code qui puissent être réutilisé avec n'importe quel compilateur sur n'importe quel système. C'est cela que l'on appelle du code portable.

En général, vous devriez vous efforcer de rendre votre code aussi portable que possible, sans quoi vous risquez de devoir récrire entièrement votre programme par la suite pour qu'il fonctionne ailleurs - et qui peut dire ce que vous utiliserez dans quelques années?

% cc -Wall -ansi -pedantic -o foobar foobar.c

Cela générera un exécutable foobar après avoir vérifié que foobar.c respecte la norme.

-lbibliothèque

Définit une bibliothèque de fonctions à utiliser pour l'édition de liens.

L'exemple le plus courant est la compilation d'un programme qui utilise certaines des fonctions mathématiques de C. A l'inverse de la plupart des autres plates-formes, ces fonctions sont dans une bibliothèque différente de la bibliothèque C standard et vous devez préciser au compilateur qu'il doit l'utiliser.

La règle est que si la bibliothèque s'appelle libquelque_chose.a, vous donnez à cc l'argument -lquelque_chose. Par exemple, la bibliothèque mathématique s'appelle libm.a, vous donnez donc à cc l'argument -lm. Un détail à connaître à propos de la bibliothèque mathématique est que ce doit généralement être la dernière sur la ligne de commande.

% cc -o foobar foobar.c -lm

Cela ajoutera à l'édition de liens de foobar des fonctions de la bibliothèque mathématique.

Si vous compilez du code C++, vous devrez ajouter -lg++, ou -lstdc++ si vous utilisez la version 2.2 de FreeBSD ou une version ultérieure, à la ligne de commande pour éditer les liens avec les fonctions de la bibliothèque C++. Au lieu de cela, vous pouvez utiliser la commande c++ au lieu de cc, qui fera la même chose à votre place. Sous FreeBSD, c++ peut aussi être appelé avec g++.

% cc -o foobar foobar.cc -lg++     Avec FreeBSD 2.1.6 et antérieurs
% cc -o foobar foobar.cc -lstdc++  Avec FreeBSD 2.2 et ultérieurs
% c++ -o foobar foobar.cc

Chacun de ces exemples construira un exécutable foobar à partir du fichier source C++ foobar.cc. Remarquez que, sur les systèmes Unix, les fichiers sources C++ ont traditionnellement l'extension .C, .cxx ou .cc, plutôt que l'extension .cpp de sytle MS-DOS™ (qui est déjà utilisée pour autre chose). gcc se fiait autrefois à l'extension pour savoir quel type de compilateur utiliser avec le fichier source, mais cette restriction ne s'applique plus, vous pouvez donc appeler vos fichiers C++ .cpp en toute impunité!

3.1. Questions et problèmes cc

Q. J'essaie d'écrire un programme qui utilise la fonction sin() et j'obtiens une erreur qui ressemble à ce qui suit. Qu'est-ce que cela veut dire?

/var/tmp/cc0143941.o: Undefined symbol `_sin' referenced from text segment


R. Quand vous utilisez des fonctions mathématiques telles que sin(), vous devez dire à cc d'inclure la bibliothèque mathématique à l'édition de liens, comme ceci:

% cc -o foobar foobar.c -lm


Q. D'accord, j'ai écrit ce petit programme pour m'entraîner à utiliser -lm. Il ne fait que calculer 2.1 à la puissance 6:


#include <stdio.h>

int main() {
      float f;

      f = pow(2.1, 6);
      printf("2.1 ^ 6 = %f\n", f);
      return 0;
}
           
et l'ai compilé comme ceci:
% cc temp.c -lm
comme vous avez dit qu'il fallait le faire, mais voilà ce que j'obtiens à l'exécution:
% ./a.out
2.1 ^ 6 = 1023.000000


Ce n'est pas la bonne réponse! Que se passe-t-il?

R. Quand le compilateur voit que vous appelez une fonction, il regarde s'il en a déjà vu un prototype. Si ce n'est pas le cas, il suppose que la fonction retourne un int - entier, ce qui n'est évidemment pas ce que vous souhaitez dans ce cas.

Q. Comment alors régler ce problème?

R. Les prototypes des fonctions mathématiques sont dans math.h. Si vous incluez ce fichier, le compilateur trouvera le prototype et cessera de vous fournir un résultat bizarre!


#include <math.h>
#include <stdio.h>

int main() {
...
           


Après l'avoir recompilé de la même façon qu'auparavant, exécutez-le:

% ./a.out
2.1 ^ 6 = 85.766121


Si vous utilisez la moindre fonction mathématique, incluez toujours math.h et n'oubliez pas d'utiliser la bibliothèque mathématique à l'édition de liens.

Q. J'ai compilé un fichier appelé foobar.c et je ne trouve pas d'exécutable appelé foobar. Où est-il passé?

R. N'oubliez pas, cc appellera l'exécutable a.out à moins que vous ne lui disiez de faire autrement. Utilisez l'option -o nom_de_fichier:

% cc -o foobar foobar.c


Q. OK, si j'ai un exécutable appelé foobar, je le vois avec ls, mais quand je tape foobar sur la ligne de commande, il me dit que le fichier n'existe pas. Pourquoi ne le trouve-t-il pas?

R. A l'inverse de MS-DOS, Unix ne regarde pas dans le répertoire courant quand il cherche le programme que vous voulez exécuter, à moins que vous ne le lui disiez. Soit tapez ./foobar, ce qui veut dire “exécuter le fichier appelé foobar du répertoire courant”, ou modifiez votre variable d'environnement PATH pour qu'elle ressemble à:

bin:/usr/bin:/usr/local/bin:.
Le dernier point signifie “chercher dans le répertoire courant si le fichier n'est pas dans les autres répertoires”.

Q. J'ai appelé mon exécutable test, mais il ne se passe rien quand je le lance. Pourquoi?

R. Il y a un programme appelé test dans /usr/bin sur la plupart des systèmes Unix et c'est celui-là que trouve l'interpréteur de commandes avant de regarder dans le répertoire courant. Soit tapez:

% ./test
ou choisissez un meilleur nom pour votre programme!

Q. J'ai compilé et tout a commencé à fonctionner correctement, puis il y a eu une erreur et il m'a dit quelque chose à propos de “core dumped”. Qu'est-ce que cela veut dire?

A. L'expression core dump date des tous premiers jours d'Unix, quand les machines utilisaient la mémoire centrale - “core memory” pour stocker les informations. Essentiellement, si le programme “plantait” dans certaines conditions, le système enregistrait sur disque le contenu de la mémoire centrale dans un fichier appelé core, que le programmeur pouvait ensuite disséquer pour trouver où les choses avaient mal tournées.

Q. Fascinant, mais que suis-je censé faire maintenant?

A. Servez-vous de gdb pour analyser l'image mémoire (Reportez-vous à la section Déboguer).

R. Quand mon programme a généré une image mémoire, il a dit quelque chose à propose de “segmentation fault” - “erreur de segmentation”. Qu'est-ce que c'est?

Q. Cela signifie essentiellement que votre programme a essayé d'effectuer une quelconque opération illégale sur la mémoire; Unix est conçu pour protéger le système d'exploitation des programmes mal éduqués.

Les raisons les plus courantes en sont:



Commettre l'une de ces fautes ne provoquera pas toujours une erreur, mais ce sont malgré tout des choses à ne pas faire. Certains systèmes et compilateurs sont plus tolérants que d'autres, ce qui fait que des programmes qui s'exécutent correctement sur un système peuvent ne plus fonctionner sur un autre.

Q. Parfois, le programme provoque la génération d'une image mémoire avec le message “bus error”. Mon manuel Unix dit qu'il s'agit d'un erreur matériel, mais l'ordinateur fonctionne apparemment correctement. Est-ce vrai?

R. Fort heureusement, non (à moins bien sûr que vous n'ayez aussi un problème matériel). C'est habituellement une autre façon de dire que vous avez accédé incorrectement à la mémoire.

Q. Il me semble que cette histoire de core dump peut être très utile, si je peux la provoquer quand je veux. Est-ce possible, ou dois-je attendre qu'il se produise une erreur?

R. Oui, allez simplement sur une autre console ou fenêtre xterm et tapez:

% ps
pour connaître l'IDentifiant de processus de votre programme, puis:
% kill -ABRT pid
pid est l'ID de processus que vous avez recherché.

C'est par exemple utile si votre programme est parti dans une boucle infinie. Au cas où votre programme piégerait les interruptions SIGABRT, il y a plusieurs autres signaux qui auront le même effet.

Notes

[1]

Pour être rigoureusement exact, cc convertit le code source en un P-code qui lui est propre, et ne dépend pas de la machine, et non en assembleur à ce stade.

[2]

Au cas où vous ne le sauriez pas, un tri par arbre binaire est une manière efficace d'ordonner des données, ce qui n'est pas le cas du tri à bulles.

[3]

Les raisons de cela se sont perdues dans les brumes de l'histoire.

[4]

Remarquez que nous n'avons pas utilisé l'indicateur -o pour préciser le nom de l'exécutable, celui-ci s'appellera donc a.out. Générer une version débogable appelée foobar est laissé à titre d'exercice aux soins du lecteur!

Ce document, ainsi que d'autres peut être téléchargé sur ftp.FreeBSD.org/pub/FreeBSD/doc/.

Pour toutes questions à propos de FreeBSD, lisez la documentation avant de contacter <questions@FreeBSD.org>.
Pour les questions sur cette documentation, contactez <doc@FreeBSD.org>.