Université
Joseph Fourier IMA |
Année
Universitaire 2003-2004
M1 Info OPL –Outils
de Production de Logiciels TP |
Concepteur: Didier DONSEZ
TP – Make
Liens :
http://www-adele.imag.fr/~donsez/cours/make.pdf
http://www.infres.enst.fr/~dax/polys/make/
http://www.april.org/groupes/doc/make/make.html
http://www.cmi.univ-mrs.fr/~contensi/coursC/environnement/make.html
http://www.lifl.fr/~marquet/ens/uu/uu078.html
Vous connaissez certainement la commande cc (ou gcc qui est libre de droit) qui vous permet de compiler un source C pour produire un exécutable (a.out).
Mais connaissez vous l’organisation d’un projet utilisant la compilation séparée ou bien encore la création de bibliothèque de fonctions, ... ? Non, ce n’est pas grave : ce TP devrait vous éclairer.
Soit le source all.c dont la fonction importe peu :
#include <stdio.h>
#define LIMIT 10000000
#define DIX 10
typedef char* CHAINE;
void affichdeb(CHAINE c) {
printf("fin de %s\n", c);
}
void affichfin(CHAINE c) {
printf("deb de %s\n", c);
}
void fnc21(){
affichdeb("fnc21"); affichfin("fnc21");
}
void fnc22(){
affichdeb("fnc22"); affichfin("fnc22");
}
void fnc1(){
affichdeb("fnc1"); fnc21(); fnc22();
affichfin("fnc1");
}
int boucle(){
int
i1=1 ; int i2=1 ; int i0=1 ; int i ;
for(i=0;i<LIMIT ;i++) {
i2=i1+i0 ;
i1=i0+1
i0=i0+1
}
return i2 ;
}
int bouclelimit(int
limit){
int
i1=1 ; int i2=1 ; int i0=1 ;
for(int i=0 ;i<limit ;i++) {
i2=i1+i0 ;
i1=i0+1 ;
i0=i0+1 ;
}
return i2 ;
}
void boucles(int nb,int
limit){
int tmp ;
for(int
y=0 ;y<nb ;y++) {
tmp+=tmp+bouclelimit(LIMIT)+boucle() ;
}
printf("boucles %d\n", tmp);
}
static int nbstatic=DIX;
int main(int argc, char**
argv){
affichdeb("main"); fnc1();
fnc21();
boucles(nbstatic,LIMIT);
affichfin("main");
}
Partie 1 : Débuggeur et
Performance
Ex1.1: Débuggeur
Après avoir compiler ce programme avec l’option –g (ou –ggdb)
Lancez le débuggeur gdb (ou dbx) sur l’exécutable produit.
Posez un point d’arrêt dans la fonction boucles() (break boucles)
Démarrer le programme (run)
Visualiser la valeur de la variable y et tmp (print tmp) en exécutant le programme en pas à pas.(step)
Visualiser la pile (backtrace)
Poursuivre l’exécution (continue)
L’ensemble des commandes de gdb est donné par la commande help.
Ex1.2: Traces
Tracer l’exécution du programme au moyen des 3 commandes suivantes
Ex1.3: Performance sans
optimisation
A quoi sert la commande time ? Utilisez time avec votre exécutable
A quoi sert l’option –p de compilation ?
Après avoir compiler ce programme sans l’option d’optimisation et avec l’option -p,
Lancez l’exécutable qui produit un fichier mon.out ou gmon.out
Lancez prof ou gprof pour fournir statistiques et comptages
Que signifie chacune de ces valeurs ?
Ex1.4: Performance avec
optimisation
A quoi sert l’option –O2 de compilation ?
Après avoir compiler ce programme avec l’option d’optimisation –O2, utilisez la commande time sur l’exécutable optimisé. Notez vous une différence de temps d’exécution ?
Après avoir compiler ce programme avec l’option d’optimisation –O2 et avec l’option -p, lancez l’exécutable qui produit un fichier mon.out ou gmon.out
Lancez prof ou gprof pour fournir statistiques et comptages
Comparez avec les résultats du 1.3 ?
Ex1.5: Compilation et
Compilateur
Rappelez les différences phases d’une compilation d’un programme C.
Testez l’option -v de gcc ou cc sur le source C
Quelles sont les différentes commandes qui sont enchaînées ?
A quoi sert la commande cpp ?
Que produisent ces différentes options de gcc :
-E, -S, -c
Regardez le contenu de chaque fichier produit
Partie 2 : MAKE
Ex2.1: Makefile
implicite
Que font les commandes make all.o et make "CC=gcc" all.o alors qu’il n’y a pas de Makefile dans le répertoire courant.
Regardez le contenu du fichier /usr/share/lib/make/make.rules
A quoi sert
il ?
Ex2.2: Compilation
Séparée
A quoi sert les fichiers “header” .h
Repartissez les fonctions du programme précédent dans plusieurs fichiers de la manière suivante:
affichdeb() affichfin() dans affich.c
main(), boucles(), boucle(),
bouclelimit(), nbstatic dans main.c
fnc1() dans f1.c
fnc21() et fnc22() dans f2.c
Pensez à définir les .h associés à ces fichiers. Que doivent ils contenir ?
Donner la commande permettant la compilation de ces 4
fichiers afin de produire un exécutable prog.exe.
Ecrire le script shell compil.sh qui enchaîne les commandes de compilation séparées produisant des .o et effectuant finalement une édition de lien de ce .o
Remarque : pour éviter les erreurs de redéfinitions dans les fichiers .h, utilisez les macros CPP conditionnelles comme dans l’exemple suivant.
/* affich.h */
#ifndef _HEADER_AFFICH
#define _HEADER_AFFICH 1
typedef char* CHAINE;
extern void
affichdeb(CHAINE);
extern void affichfin(CHAINE);
#endif
Ex2.3: Inspection des
objets et de l’exécutable
A quoi sert la commande nm ?
Appliquez la sur chacun des objets produits .o et sur l’exécutable prog.exe
Qu’est devenu le point d’entrée nbstatic (pourquoi ?)
A quoi sert l’option –s de la commande ld ? Verifiez le résultat produit sur l’édition de lien produisant prog.exe. Quel peut être son usage ?
Ex2.4: Makefile
La commande make permet d’exécuter des commandes en fonction du graphe de dépendance entre les fichiers. La régle d’exécution est la suivante :
si une cible (à gauche) n’existe pas ou est plus ancienne qu’une des sources (à droite), la commande est effectuée.
Documentez vous sur make et les makefiles
Définissez le makefile permettant de remplacer compil.sh
Raffinez votre makefile pour obtenir le moins de règles possibles et en utilisant des règles génériques.
Raffinez votre makefile pour archiver les .o dans un répertoire ./obj et vos .c .h dans un répertoire ./src avec proj.exe en ./bin
Raffinez votre makefile pour archiver vos .c .h dans un répertoire ./src, les .o dans un répertoire ./obj, les .o avec les informations de déboggage en ./obj.g, les .o optimisés dans ./obj.O2 et les différentes alternatives de proj.exe en ./bin
Ex2.5: Makedepend
makedepend analyse les sources contenant des macro d’inclusion en vue de produire les dépendances pour les Makefiles
Documentez vous sur makedepend
Utiliser makedepend pour produire les dépendances de votre programme.
Integrer au makefile en prévoyant une cible “depend”
Ex 2.6: Bibliothèques
de fonctions
Quand des fonctions sont utilisées régulièrement dans vos programmes, il peut être intéressant de conserver les objets de celles-ci dans une “bibliothèque” qui est un format de fichiers regroupant plusieurs objets.
Documentez vous sur les commandes ar et ranlib
Créez une bibliothèque libmabib.a
regroupant f21.c
f22.c
Utilisez libmabib.a pour produire prog.exe
Modifiez votre makefile pour produire automatiquement libmabib.a
Utilisez la commande nm pour inspecter le contenu des fichier .o .a produits
Quelle est la différence entre une bibliothèque statique et une bibliothèque dynamique ?
Ex 2.7: Un autre
Makefile
Le programme calculatrice évalue des expressions arithmétiques (simples).
Cette calculatrice est écrite en C et utilise des analyseurs générés par lex et yacc.
Sa production est donnée par le script shell suivant :
#!/bin/sh
lex -t psql.l >
psql_l.c
yacc -d psql.y
mv y.tab.c psql.c
mv y.tab.h psql.h
cc -o sql2perl psql.o
psql_l.o main.o action.o -ll
cd TEST
make gen test
Donnez le Makefile qui produit calculatrice.
Sous Linux, les outils GNU flex et bison remplacent les analyseurs lex et yacc et flex utilise la bibliothèque libfl.
Faites en sort que votre makefile supporte à la fois lex/yacc et flex/bison
Ex 2.8: Complément
Vous pourrez tester en complément les exemples fournis avec l’ouvrage de Andy Oram et Steve Talbott, « Managing Projects with make, 2nd Edition », Ed Oreilly, Octobre 1991, 0-937175-90-0 disponibles sur http://www.oreilly.com.
Ex 2.7: Imake
Réalisez le Imakefile pour votre projet de l’exercice 2.2
Partie 3: Gestion des
versions de source (extra)
La commande sccs permet de gérer des versions de sources.
Avec les fichiers précédents amusez vous à modifier les fichiers de sources, sauvegarder une version, à revenir sur une version en recompilant ces versions à chaque coup.
Pour info, CVS est un outil distribué de gestion de versions permettant à plusieurs développeurs de collaborer par le Web au développement d’un logiciel.