2.11. Appel d'un compilateur C

La notice d'utilisation succincte d'un compilateur C est la suivante :
cc compile les fichiers se terminant par '.c', assemble ceux qui se terminent par '.s' et passe les options non mentionnées ci-dessous à l'éditeur de lien 'ld'.
utilisation : cc [options] fichier ...
options :
-c	compile seulement, sans édition de liens; les fichiers objets ont pour nom celui obtenu en remplaçant '.c' ou '.s' par '.o'
-Dchaine[=valeur] demande au préprocesseur de définir 'chaine' avec 'valeur'
-Uchaine demande au préprocesseur de retirer toute définition initiale de 'chaine'
-Ichemin demande de rechercher les fichiers 'include'dans le répertoire 'chemin'
-E	demande de lancer seulement le préprocesseur et d'écrire sa sortie sur stdout
-S	demande de compiler en langage d'assemblage, sans assembler; les fichiers résultats ont pour nom celui obtenu en remplaçant '.c' par '.s'
-g	demande de produire les informations de mise au point
-O2	demande d'optimiser le code
A- Décrire brièvement les étapes essentielles de la production de programme.
B- Dans ce contexte, expliquer l'option -c et la commande suivante :
	cc -c toto.c
C- Décrire le rôle d'un préprocesseur et expliquez les options -D, -U, -I. Comment interprétez-vous les deux commandes suivantes :
	cc -DBUFSIZE=2048 -DUNIX -c schmilblick.c
	cc -DBUFSIZE=1024 -DMS_DOS -c schmilblick.c
D- Décrire brièvement les fonctions du metteur au point, et expliquer le rôle de l'option -g dans la chaîne de production de programme.
E- Quel est le rôle de l'option -O2? Expliquer la commande suivante :
	cc -O2 toto.c -o toto
F- Expliquer l'utilité des options -E et -S.
Solution de l'exercice 2.11.

2.11.1. Question A.

La construction d'un programme se fait souvent de façon modulaire. En effet, dès qu'il est d'une certaine taille, il est nécessaire de le morceler, pour manipuler des entités cohérentes et dont on maîtrise la complexité. Le découpage modulaire permet aussi la réutilisation des modules dans différents programmes. Ces modules peuvent être écrits dans différents langages (évolués ou d'assemblage). Chacun d'eux doit alors être traduit pour donner un module objet de sémantique équivalente, mais dans un langage intermédiaire proche du langage de la machine. C'est le rôle des compilateurs ou des assembleurs d'assurer cette traduction. Ces modules objets doivent ensuite être regroupés pour constituer un programme exécutable. C'est le rôle de l'éditeur de liens d'une part de translater les modules pour qu'ils puissent résider dans des emplacements de mémoire centrale différents, et d'autre part de résoudre les liens entre les modules, en associant les liens à satisfaire d'un module avec un lien utilisable situé dans un autre module. Enfin, le programme exécutable doit être mis en mémoire centrale pour son exécution. C'est le rôle du chargeur d'assurer cette mise en mémoire (translation finale éventuelle) et de préparer son environnement d'exécution (construction de la machine abstraite).

2.11.2. Question B.

La notice d'utilisation précise dès le début que cc assure la compilation des modules écrits en langage C, l'assemblage des modules en langage d'assemblage et l'édition de liens de l'ensemble des modules. En d'autres termes, il s'agit d'un programme qui enchaîne l'ensemble des activités de la chaîne de production de programme, à l'exception du chargement. Cela facilite la construction des programmes constitués de peu de modules.
L'option permet d'empêcher cet enchaînement lorsque le programme final est constitué de plusieurs modules qui sont compilés séparément. Elle est particulièrement utile lorsqu'on utilise des outils automatiques comme le make qui détermine les opérations strictement nécessaires à la construction d'un programme en évitant celles qui ne sont pas utiles.
Ainsi la commande cc -c toto.c est une demande de compilation sans édition de liens du fichier toto.c. Le résultat sera mis dans le fichier toto.o.

2.11.3. Question C.

Le rôle du préprocesseur est de faire un traitement sur le texte source lui-même avant la compilation proprement dite. Il permet de paramétrer le texte source, et de fixer les valeurs des paramètres au moment de la compilation. Un même texte source peut alors être utilisé dans diverses situations, comme on le montrera avec les deux commandes. En particulier, le préprocesseur réalise essentiellement trois modifications :
L'option -D permet précisément de donner une définition à une chaîne, valable pour cette compilation, sans modifier le fichier source lui-même. Evidemment, ceci n'a de sens que si le fichier source fait référence à cette chaîne.
L'option -U permet de supprimer une définition présente dans le fichier, pour cette compilation.
L'option -I permet de préciser le répertoire où il y a lieu de rechercher les fichiers qui sont mentionnés dans une clause '#include' du fichier source. C'est particulièrement utile pour permettre de regrouper dans un répertoire spécifique les fichiers utilisés en inclusion.
Les deux commandes suivantes concernent la compilation du même fichier en langage C.
cc -DBUFSIZE=2048 -DUNIX -c schmilblick.c
cc -DBUFSIZE=1024 -DMS_DOS -c schmilblick.c
Elles définissent d'une part la chaîne BUFSIZE comme une constante avec des valeurs différentes dans les deux cas et d'autre part deux chaînes différentes sans leur donner de valeur. La première définit la chaîne UNIX, et la seconde la chaîne MS_DOS. Ces deux chaînes seront plutôt utilisées, dans le fichier, pour insérer ou supprimer du texte. Intuitivement, le fichier schmilblick.c contient un module qui est paramétré pour être compilé soit pour un système UNIX, soit pour un système MS_DOS. La première commande produira le module objet adapté à UNIX, alors que la seconde produira celui adapté à MS_DOS. Répétons que ceci n'a de sens que si le fichier contient des clauses '#ifdef UNIX' ou '#ifdef MS_DOS'.

2.11.4. Question D.

Des outils ont été construits pour permettre la mise au point d'un programme. Ces outils sont appelés metteurs au point. Les fonctionnalités essentielles sont les suivantes :
Il est plus facile pour l'utilisateur de désigner les points d'arrêt ou les variables sous une forme proche du langage dans lequel il a écrit les modules, c'est-à-dire sous forme symbolique, en utilisant les identificateurs des modules. Pour cela, il faut que le metteur au point puisse faire la transformation entre ces identificateurs et les adresses en mémoire centrale. Ceci nécessite la coopération entre les constituants essentiels de la chaîne de production de programme. L'option -g demande au compilateur de rajouter dans le module objet les informations qui sont utiles au metteur au point, comme par exemple, la table des symboles et la table des numéros de lignes. Ces informations seront modifiées par l'éditeur de liens qui tiendra compte des translations effectuées, et les mettra dans le fichier qui contient le programme exécutable, où le metteur au point ira les chercher.

2.11.5. Question E.

L'écriture des modules dans un langage évolué implique une description de haut niveau, éloignée des contraintes matérielles. L'optimisation est une opération effectuée par le compilateur sur le code produit de façon à en améliorer l'efficacité. C'est une opération coûteuse en temps, car elle est complexe. Elle est inutile sur des modules qui ne sont pas complètement au point. Elle peut d'ailleurs perturber la mise au point car elle peut entraîner des déplacements d'instructions et des suppressions de variables. C'est pourquoi elle doit être optionnelle.
La commande cc -O2 toto.c -o toto est une demande de compilation du fichier toto.c. Le résultat sera mis dans le fichier toto.o. Cette compilation doit se faire avec optimisation de code. Ensuite l'éditeur de liens est appelé sur le fichier toto.o, avec les options -o toto. On peut penser que cette option permet de donner le toto au fichier résultat de l'édition de liens.

2.11.6. Question F.

L'option -E permet de consulter le résultat du traitement du texte source par le préprocesseur. On peut y voir deux intérêts. D'une part, lorsque le texte source contient des commandes complexes au préprocesseur, cela permet de vérifier leur bonne interprétation. D'autre part, cela permet d'utiliser le préprocesseur lui-même sur des textes quelconques, qui ne sont pas des modules en langages C. Si on désire conserver le résultat du traitement, il suffira alors de rediriger la sortie stdout vers un fichier.
L'option -S permet d'obtenir le résultat de la compilation en langage d'assemblage. Son utilité est en général réservé à des spécialistes. D'une part, Elle permet de se servir du compilateur comme première étape de préparation d'un module en langage d'assemblage, qui est ensuite adapté et modifié selon les besoins. Si le compilateur est doté d'un bon optimiseur, cette possibilité est souvent d'un intérêt limité. D'autre part elle permet de connaître le code produit par le compilateur sous une forme lisible, ce qui peut s'avérer parfois utile dans des situations de mise au point difficiles.