La facturation qui ne se construit plus
Le logiciel de facturation d’une PME ne se construit plus. Le message dit undefined reference to printf. Un développeur relit le code C ligne par ligne pendant une heure.
Le code est juste. Le message vient de la toute dernière étape, qui ne lit jamais le code. Savoir qui parle, et à quelle étape, lui aurait fait gagner cette heure.
À la fin de cette leçon
Remarque
Je peux nommer les étapes par lesquelles un compilateur fait passer un programme.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Pilote | un programme qui lance les autres outils dans l’ordre | gcc |
| Préprocesseur | l’étape qui colle des fichiers et remplace les macros | |
| Macro | un nom que le préprocesseur remplace par un texte | GREETING |
| Assembleur | le programme qui traduit l’assembleur en code machine | as |
| Fichier objet | du code machine qui n’est pas encore un programme entier | hello.o |
| Éditeur de liens | le programme qui assemble fichiers objets et bibliothèques | ld |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
gcc fait travailler d’autres programmes
Quand vous tapez gcc hello.c, gcc fait très peu de travail lui-même. C’est un pilote : il lance d’autres programmes, l’un après l’autre. Chacun reçoit le fichier écrit par le précédent.
L’option -### demande à gcc d’afficher ces commandes sans en lancer aucune. Comparez les deux Runs : le second ajoute la dernière étape, que -c supprime.
Aller dans le dossier du compilateur
cd ~/compilerAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Les programmes lancés avec -c
gcc -### -c hello.c 2>&1 | grep "^ " | cut -d " " -f 2Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Les programmes lancés sans -c
gcc -### -o hello hello.c 2>&1 | grep "^ " | cut -d " " -f 2Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Le préprocesseur colle et remplace
La première étape ne comprend pas le C. Le préprocesseur suit les lignes qui commencent par #. #include colle le contenu d’un autre fichier. #define déclare une macro, un nom à remplacer par un texte.
gcc -E s’arrête juste après cette étape. Le premier Run montre la macro dans le source. Le second montre la fin du texte prétraité.
Où la macro apparaît
grep -n "GREETING" hello.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
La fin du texte prétraité
gcc -E hello.c | tail -n 11Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Garder le fichier de chaque étape
D’habitude, les fichiers intermédiaires vont dans un dossier temporaire et sont effacés. L’option -save-temps les garde à côté du source.
Une seule construction laisse alors quatre fichiers. La commande file lit le début de chacun et dit de quel genre il est.
Construire une fois et tout garder
gcc -save-temps -o hello hello.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Quel genre de fichier est chacun ?
file hello.i hello.s hello.o helloAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Exemple travaillé : ce que file a répondu
| Fichier | Écrit par | Ce que file en dit |
|---|---|---|
| hello.i | Le préprocesseur | C source, ASCII text |
| hello.s | Le compilateur | assembler source, ASCII text |
| hello.o | L’assembleur | ELF 64-bit LSB relocatable |
| hello | L’éditeur de liens | ELF 64-bit LSB pie executable |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Un fichier objet laisse des trous
hello.o contient le code machine de square et de main. Mais main appelle printf, qui n’est pas dans ce fichier. Il vit dans la bibliothèque C.
nm -u liste les symboles non définis : les noms que l’éditeur de liens devra trouver ailleurs. Lancez ensuite l’éditeur de liens ld vous-même, sans la bibliothèque C, et lisez sa réponse.
Les symboles qui manquent à hello.o
nm -u hello.oAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Lier sans rien d’autre
ld hello.o -o casseAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Erreur fréquente
Attention
Beaucoup de gens pensent que toute erreur de construction vient d’une faute dans leur code. Un undefined reference vient de l’éditeur de liens, après une compilation réussie. Le code d’un symbole n’a pas été fourni à la dernière étape. Vérifiez ce qui est lié, pas la ligne de C.
D’où vient printf
ldd helloAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Pour aller plus loin
Tapez ceci vous-même. Avec sed, faites une copie de hello.c nommée cube.c où square(7) devient cube(7). Aucune fonction cube n’existe.
Construisez avec gcc -c cube.c et notez quelle étape refuse. Ajoutez ensuite la ligne int cube(int n); avant main, puis relancez gcc -c cube.c et gcc cube.c. Expliquez pourquoi les deux erreurs viennent de deux étapes différentes.