La compilation
Définition : La compilation
La locution compilation de programme est souvent utilisée à la place de « génération d'exécutable ». En effet, cette dernière comprend :
La détermination des étapes de compilation,
Le prétraitement des fichiers sources fournissant des sources « complets »,
La compilation des fichiers issus de l'étape précédente produisant des fichiers de « code machine »,
La création des liens qui résout les appels au sein des fichiers code ou vers les bibliothèques par défaut et celles explicitement choisies, générant le code exécutable.
Bien sûr, le code exécutable n'est généré que dans le cas où il n'y a pas d'erreurs d'écriture du programme. Dans le cas contraire, nous avons des messages d'erreurs.
La compilation comprend également plusieurs étapes d'analyse :
Analyse lexicale : vérification que les caractères ou suites des caractères du programme sont des constituants d'un programme du langage cible (ici le langage C). Cette phase découpe le flux de caractères du fichier en une suite d'unités lexicales prise en compte par l'étape suivante,
Analyse syntaxique : vérification que l'ordonnancement des unités lexicales respecte une configuration possible décrite par une grammaire (la grammaire du langage C),
Analyse sémantique : vérification que les opérations décrites par la suite d'instructions ont un sens pour les données manipulées. Par exemple, comparer une donnée simple, comme un entier à un ensemble de données, comme les caractéristiques d'un individu, n'a pas de sens, même si la grammaire permet l'écriture d'une instruction semblable.
Bien que conceptuellement les phases d'analyse soient distinctes, elles sont imbriquées dans le processus de compilation.
Les différentes étapes
Le prétraitement
Ce traitement est réalisé par le pré-compilateur. Celui-ci parcourt le code, détecte les instructions qui lui sont destinées et réalise des substitutions de texte.
Les instructions de prétraitement sont des lignes commençant par le caractère #.
La plus connue et utilisée est l'instruction #include qui se traduit par un remplacement de la ligne par le contenu du fichier mentionné dans l'instruction.
D'autres macro-instructions de prétraitement permettent d'intégrer ou non des séquences du code source, en fonction des conditions liées au système, au compilateur ou à l'application. Il est également possible de définir des modèles de suite des caractères à remplacer par d'autres dans le code source qui suit.
Ce pré-compilateur est un interprète de commande d'un langage. On parle du langage MACRO. Celui-ci reste très limité par rapport au langage C.
Les opérations de prétraitement ou « macro-instructions » étant des inclusions de codes sources, des substitutions de suite des caractères ou des suppressions de lignes, le résultat de cette étape est toujours du langage C et constitue le programme C soumis au compilateur.
La compilation effective
Traduction du programme C en langage machine. Le résultat de la compilation porte le nom de fichier objet. Le nom effectif du fichier correspond au fichier source avec cependant le suffixe .o à la place de .c du code source. Cette étape est réalisée en plusieurs phases non visibles par l'utilisateur : analyse lexicale, analyse syntaxique, analyse sémantique puis génération code.
L'édition des liens
Utilisation des fichiers objets de la bibliothèque standard C et des bibliothèques utilisateurs éventuelles pour créer le programme exécutable.
Remarque : Attention aux faux positifs !
Sauf indication contraire, ces étapes sont enchaînées automatiquement dans l'ordre cité ci-dessus. En cas d'erreurs, pour donner à l'utilisateur le plus d'information possible, les outils d'analyse notent l'erreur et tentent de reprendre la détection des erreurs. Dans le cas d'erreurs en phase d'analyse lexicale, le processus de compilation s'arrête et donne la possibilité au programmeur de corriger le fichier source.
Ce fonctionnement de la compilation peut aboutir :
À la non-détection de certaines erreurs intégrées à du code « ignoré » dans une étape de reprise de l'analyse,
À la génération d'erreurs résultantes de la non-compréhension du code renfermant une erreur ou de la non-prise en compte d'un code « ignoré ».
La solution simpliste est de relancer la compilation à la suite de la correction de la première erreur. La pratique montrera que cette solution est peu efficace et rébarbative par la présence de boucles correction/compilation. Une pratique de l'analyse des erreurs permettra rapidement de distinguer les vraies des fausses erreurs et on réservera la relance de la compilation aux cas complexes ou présentant un nombre d'erreurs visiblement disproportionné.
Attention : Une erreur incompréhensible !
Chaque étape de la génération peut rencontrer un problème et générer une erreur. C'est notamment le cas de l'éditeur de liens. Ainsi, l'utilisation d'une fonction de bibliothèque dont nous avons intégré les prototypes de fonctions par une instruction macro d'inclusion, peut provoquer une erreur, si l'on oublie d'intégrer dans les ressources de l'éditeur de liens l'accès à la bibliothèque correspondante.
Dans ce cas, la compilation proprement est réussie, mais l'édition des liens échoue. Le message d'erreurs est précédé par le terme « ld » précisant l'origine du signalement de l'erreur.
Inutile donc de parcourir le code source pour résoudre le problème. Il faut modifier des directives de compilation de votre programme.