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.

Vous pouvez utiliser les « front-ends » graphiques de ces debuggeurs (xdbx, xxgdb, ddd) s’ils sont installés

 

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.