original in nl Wilbert Berendsen
nl to en Philip de Groot
en to fr Iznogood
Wilbert Berendsen est un professeur de musique et un utilisateur de Linux enthousiaste. Autrefois, il programmait beaucoup en assembleur pour le Z80. Aujourd''hui, il utilise Linux pour tout son travail. Simplement pour le plaisir, il écrit des articles d'introduction et maintient un petit site web sur http://www.xs4all.nl/~wbsoft/. Viva open source!
A peu près toutes les personnes qui utilisent Linux ont un jour fait appel au programme make. Il fait ce qu'on attend de lui lors de la construction d'un programme ou du noyau à partir du code source, lors de l'installation d'un paquetage, ainsi de suite. 'Make' est un outil important pour le développement logiciel. Il possède, néanmoins, beaucoup d'autres capacités!
Dans ce document, nous verrons que make peut être très puissant pour le travail de tous les jours, tel qu'écrire des articles, des livres ou créer un joli site web. Pendant cette introduction, plusieurs autres 'trucs' d'Unix seront abordés. A la fin de l'histoire, quelques trucs supplémentaires seront présentés sur l'utilisation de make. Remarque : nous parlons de Linux mais en principe, il est possible d'utiliser make sur tout système d'exploitation.
Nous avons besoin d'un système simple pour séparer l'apparence du contenu. Une solution puissante est : lire le contenu à partir d'une base de données, à chaque fois que la page est demandée. Par exemple, PHP et Microsoft Active Server Pages fonctionnent de cette manière. Nous n'avons néanmoins que la possibilité de stocker du HTML (HyperText Markup Language). De plus, le contenu ne doit pas changer trop souvent pour maintenir la base de données de manière efficace.
Un site web sera construit en utilisant des commandes simples, .
Par exemple, Piet met l'en-tête du site dans header.html et le contenu du pied de page dans footer.html. header.html peut ressembler à ceci :
<html><!-- l'en-tête --> <head> <title>Productions Piet et Jan</title> </head> <body bgcolor="white"> <table border="0" width="100%"><tr> <td bgcolor="#c040ff" valign="top"> Ceci est notre site<br> Quelques bricoles écrites ici.<br> Nous sommes très interactifs<br> donc c'est notre numéro de téléphone :<br> <b>0123-456789</b> </td><td valign="top"> <!-- Mettre le contenu ici -->Et ici footer.html:
<!-- le pied de page --> </td></tr></table> </body></html>Par exemple, les commandes Unix pour fabriquer la page finale à partir de l'index.html de Jans sont :
cat header.html /home/jan/Docs/website/index.html echo -n '<hr>Dernière modification: ' date '+%A %e %B' cat footer.htmlRéférez-vous aux pages de manuel de ces commandes. Le fichier final, résultat des commandes ci-dessus, est "pipé" vers la sortie standard, qui est stockée dans un fichier :
{ cat header.html /home/jan/Docs/website/index.html echo -n '<hr>dernière odification: ' date '+%A %e %B' cat footer.html } > /home/piet/public_html/index.htmlCette procédure peut être répétée avec l'autre fichier, offer.html. En fait nous créons un petit script qui permet la construction de notre site web.
Néanmoins, exécuter manuellement cette commande n'est pas réalisable. Nous pouvons créer un script shell qui est exécuté à chaque fois que Jans a mis à jour son index. Néanmoins, si Piet décide de changer l'en-tête ou le pied de page, ce script doit aussi être exécuté! D'un autre coté, si Jans n'a rien changé pendant une journée, le script ne doit pas être exécuté. Nous utilisons Linux, nous voulons donc utiliser une solution élégante (comprendre : automatique)!
C'est là que make intervient.
make détermine comment un jeu de commandes doit être exécuté, en fonction de la date du fichier cible et de la date des fichiers source.En d'autres termes : si un des fichiers source, nécessaire à la création d'un fichier cible, est plus récent que ce fichier cible, un jeu de commandes est exécuté. Le but de ces commandes est de mettre à jour le fichier cible.
Le fichier cible est la 'destination' et les fichiers source sont les `conditions préalables'. Les commandes sont exécutées si l'une des `conditions préalables' est plus récente que le fichier cible (ou si la cible n'existe pas). Si toutes les conditions préalables sont plus anciennes ou possédent la même date que la cible, alors les commandes ne sont pas exécutées et la cible est considérée comme étant à jour.
Dans le répertoire de travail courant, un fichier doit être créé avec le nom Makefile. Ce fichier contient les informations nécessaires à make pour faire son travail correctement. Une fois que nous avons le Makefile, la seule chose à faire est de taper 'make', et les commandes, nécessaires pour créer un nouveau fichier cible, sont exécutées automatiquement.
Make est appelé avec la commande
make cible1 cible2 ....
cible est optionnel (si cible est omis, la première cible du Makefile est utilisée). Make cherche toujours un Makefile dans le répertoire courant. Il est possible de fournir plus d'une cible.
# Ceci est un exemple de Makefile. # Les commentaires peuvent être mis après un dièse (#). cible: conditions préalables commande cible: conditions préalables commande # etc, etc.Nous démarrons avec une cible, suivie par deux points (:) et les conditions préalables nécessaires. Dans le cas de plusieurs conditions préalables, il est possible de terminer la ligne avec un antislash (\) et de continuer sur la ligne suivante.
Sur la(es) ligne(s) suivante(s), une ou plusieurs commandes sont présentées. Chaque ligne est considérée comme une commande unique. Si vous voulez utiliser de multiples lignes pour une commande, vous devez mettre des antislashes (\) à la fin des lignes. Make reliera les commandes comme si elles avaient été saisies sur une seule ligne. Dans cette situation, nous devons séparer les commandes par un point virgule (;) de manière à éviter les erreurs dans l'exécution du shell.
Note: Les commandes doivent être indentées avec une TAB, pas avec 8 espaces!
Make lit le Makefile et détermine pour chaque cible (en commençant par la première) si la commande doit être exécutée. Chaque cible, associée aux conditions préalables et aux règles, est présentée comme une 'règle' (rule).
Si make est exécuté sans argument, seule la première cible sera exécutée.
# Ce Makefile construit le site web de Piets et Jans, les mangeurs de pommes de terre. all: /home/piet/public_html/index.html /home/piet/public_html/offer.html /home/piet/public_html/index.html: header.html footer.html \ /home/jan/Docs/website/index.html { \ cat header.html /home/jan/Docs/website/index.html ;\ echo -n '<hr>Dernière modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > /home/piet/public_html/index.html /home/piet/public_html/offer.html: header.html footer.html \ /home/jan/Docs/website/offer.html { \ cat header.html /home/jan/Docs/website/index.html ;\ echo -n '<hr>Dernière modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > /home/piet/public_html/offer.html # fin
Maintenant, nous avons trois cibles, 'all' et les fichiers index.html et offer.html du site. La seule fonction de la cible 'all' est d'avoir les deux autres comme conditions préalables. Ils sont testés tous les deux. 'all' en lui-même n'étant pas un nom de fichier, la cible 'all' sera toujours exécutée. (Plus tard, nous présenterons une manière plus élégante de définir des cibles qui ne sont pas des fichiers).
Si l'en-tête et le pied de page sont modifiés, les deux pages seront mises à jour. Si Jans modifie une de ses pages, seule la page modifiée sera mise à jour. Exécuter la commande 'make' fait le travail!
Bien sûr, le Makefile a un inconvénient : il n'est pas facile à vérifier. Heureusement, plusieurs techniques existent pour rendre les choses plus simples!
variable = valueNous nous référons à une variable avec l'expression $(variable). Si nous incorporons ceci dans un Makefile, il s'améliore :
# Ce Makefile construit le site web de Piets et Jans, les mangeurs de pomme de terre. # Répertoire dans lequel le site web est stocké : TARGETDIR = /home/piet/public_html # Répertoire de Jans : JANSDIR = /home/jan/Docs/website # Les fichiers nécessaires à la mise en page : LAYOUT = header.html footer.html all: $(TARGETDIR)/index.html $(TARGETDIR)/offer.html $(TARGETDIR)/index.html: $(LAYOUT) $(JANSDIR)/index.html { \ cat header.html $(JANSDIR)/index.html ;\ echo -n '<hr>Dernière modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > $(TARGETDIR)/index.html $(TARGETDIR)/offer.html: $(LAYOUT) $(JANSDIR)/offer.html { \ cat header.html $(JANSDIR)/index.html ;\ echo -n '<hr>Dernière modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > $(TARGETDIR)/offer.html # finC'est une bonne habitude d'utiliser des majuscules pour les variables. Maintenant, il est plus facile de changer le répertoire cible, par exemple.
Si vous voulez, il est possible de définir une autre méthode pour chaque document que vous souhaitez ajouter dans la mise en page. Que devons-nous faire si plusieurs documents doivent être ajoutés dans la même mise en page ? Le Makefile deviendrait très gros, alors que plusieurs redondances existent. Cela peut aussi être simplifié!
Si les Règles de modèle sont utilisées, la syntaxe de la ligne change; un champ de modèle est ajouté :
Multiples cibles : modèle : condition préalable condition préalable ... commandeLe modèle est une expression qui doit être applicable à toutes les cibles. Un caractère pourcentage (%) est utilisé pour incorporer les parties variables d'un nom de cible.
Un exemple:
/home/bla/target1.html /home/bla/target2.html: /home/bla/% : % commandesSi make lit ceci, la ligne est étendue sur 2 lignes. Ici, le modèle détermine quelle partie du nom de la cible est incorporée dans le signe pourcentage.
Le caractère pourcentage dans le champ des conditions préalables représente la partie qui est copiée par ce signe pourcentage.
Make décompose ce qui précède de la manière suivante :
/home/bla/target1.html: target1.html commandes /home/bla/target2.html: target2.html commandesLe caractère pourcentage dans le modèle `/home/bla/%' obtient par la cible `/home/bla/target1.html' la valeur `target1.html', étendant ainsi la condition préalable `%' à `target1.html'.
Pour notre site web, les règles suivantes seront incorporées :
$(TARGETDIR)/index.html $(TARGETDIR)/offer.html: $(TARGETDIR)/% : \ $(JANSDIR)/% $(LAYOUT)Maintenant, il nous reste un problème : comment utiliser les variables dans les commandes ? Les commandes étaient-elles légèrement différentes pour les deux cibles ?
La variable spéciale $\ est utilisée pour indiquer la première condition préalable et la variable $@ s'étend toujours à la cible courante.
En utilisant ces variables, il est possible de généraliser la règle complète comme suit :
$(TARGETDIR)/index.html $(TARGETDIR)/offer.html: $(TARGETDIR)/% : \ $(JANSDIR)/% $(LAYOUT) { \ cat header.html $< ;\ echo -n '<hr>Dernière modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > $@Voilà! Cette simple ligne fonctionne maintenant pour les deux fichiers !
Pour être complet, le Makefile entier est présenté avec quelques optimisations :
# Ce Makefile construit le site web de Piets et Jans, les mangeurs de pomme de terre. # répertoire où le site web est publié : TARGETDIR = /home/piet/public_html # répertoire de Jans : JANSDIR = /home/jan/Docs/website # Fichiers nécessaires à la mise en page : LAYOUT = header.html footer.html # Voici les pages web : DOCS = $(TARGETDIR)/index.html $(TARGETDIR)/offer.html # Ne changez rien en dessous de cette ligne ;-) # ------------------------------------------------------------- all: $(DOCS) $(DOCS): $(TARGETDIR)/% : $(JANSDIR)/% $(LAYOUT) { \ cat header.html $< ;\ echo -n '<hr>Dernière modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > $@ # finCeci commence à ressembler à ce que cela devrait être. Si d'autres documents sont ajoutés, il est facile de les incorporer dans le Makefile, en utilisant la variable DOCS, sans trop avoir de saisies à faire.
A la fin, la personne qui maintient le Makefile devrait facilement comprendre le fonctionnement, sans de poser trop de questions !
TEXTS = index.html offer.html yetanotherfile.html # Ne changez rien en dessous de cette ligne ;-) # ------------------------------------------------------------- DOCS = $(addprefix $(TARGETDIR)/,$(TEXTS)) all: $(DOCS) # etcCe que nous voyons ici est une fonction spéciale de make : au lieu d'un nom de variable, il est possible d'utiliser une expression complète entre parenthèses. De cette manière, il est possible de modifier des textes de plusieurs façons.
La commande spéciale $(addprefix prefix,list) ajoute un préfixe à chaque élément de la liste. Dans l'exemple, c'est le contenu de la variable TARGETDIR plus un slash (/).
Les objets listés sont séparés par des espaces. Pour cette raison, ce n'est pas une bonne idée de traiter des noms de fichiers avec espaces avec la commande make.
Pour conclure : au début, nous avons mentionné que la cible 'all' ne créerait pas un fichier avec le nom 'all' (cette ligne ne contient pas de commande) et comme résultat, cette cible est toujours exécutée. Mais comment gérer ce cas, si <accidentellement> un fichier existe avec ce nom, et qu'il est plus récent que tous les autres fichiers...?
Il y a une manière facile d'indiquer à make qu'une cible particulière doit être toujours exécutée et que cette cible ne correspond à aucun fichier sur le disque dur. Pour ce faire, la cible est marquée comme 'phony' (non réel). Ceci est fait comme suit :
.PHONY: allMaintenant, le Makefile complet ressemble à ceci :
# Ce Makefile construit le site web de Piets et Jans, les mangeurs de pommes de terre. # Répertoire où le site web est publié : TARGETDIR = /home/piet/public_html # Répertoire de Jans : JANSDIR = /home/jan/Docs/website # Fichier nécessaire pour la structure : LAYOUT = header.html footer.html # Voici les noms des pages web : TEXTS = index.html offer.html autrefichier.html # Ne changez rien en dessous de cette ligne ;-) # ------------------------------------------------------ DOCS = $(addprefix $(TARGETDIR)/,$(TEXTS)) .PHONY: all all: $(DOCS) $(DOCS): $(TARGETDIR)/% : $(JANSDIR)/% $(LAYOUT) { \ cat header.html $< ;\ echo -n '<hr>Dernière modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > $@ # finEnregistrez ce fichier et oubliez-le ! A partir de maintenant, il est possible de maintenir vos pages web, peut être en utilisant votre crontab et pour séparer proprement la mise en page du contenu!
Par exemple, la manière simpliste par laquelle le document est généré n'est pas sans risque d'erreurs : si Jans termine ses articles accidentellement par </body></html>, la plupart des navigateurs n'afficheront pas le pied de page créé par Piet. Si nous utilisons grep, perl ou tcl, il est possible d'ajouter quelques titres aux documents de Jans d'une manière astucieuse dans l'en-tête du site.
Bien sûr, Jans peut simplement écrire un texte et utiliser la commande sed pour changer toutes les lignes vides (retour chariot) en <P>:
sed -e 's/^\s*$/<p>/g'Jans peut aussi écrire ses textes dans LyX et utiliser un programme comme lyx2html, pour le convertir en HTML. Il existe d'extraordinaires possibilités !
Une autre modèle de construction est aussi envisageable.
Nous n'avons pas pris en considération la façon de transférer (redimensionner, convertir ou compresser) les images dans le répertoire du site. Il est aussi possible d'automatiser ce processus!
Dans cet exemple, Piet doit avoir les droits de lecture dans le répertoire du site web de Jans. L'intérêt dans la séparation de ces taches est de pouvoir les mettre en pratique dans de grosses organisations. Piet peut même se loger à l'autre bout du monde ou monter son répertoire personnel par NFS. Les exemples peuvent aussi être utilisés pour le travail effectué par un utilisateur.
Espérons que les principes de fonctionnement du Makefile sont devenus plus clairs et que votre travail quotidien sera facilité par l'écriture d'un bon Makefile !
En utilisant des cibles 'phony' (.PHONY: cible), il est facile de rassembler des fonctions simples. Un exemple est la configuration du noyau Linux.
Taper make menuconfig démarre la configuration avec un menu interactif. Taper make xconfig démarre la configuration avec une interface Tcl/Tk sous X.
Les deux cibles mentionnées ci-dessus n'ont rien à voir avec la construction réelle du noyau. Elles fournissent une interface simple aux fonctions nécessaires (comme configurer le noyau).
Vous devriez créer un Makefile avec les cibles PHONY suivantes :
De cette manière, il est possible de générer du HTML à partir d'un fichier texte et d'améliorer la mise en page du fichier HTML ainsi obtenu. Un exemple :
TEMPLATE = layout1/Template1.txt /home/httpd/sales/sales.html: sales.html $(TEMPLATE) perl Scripts/BuildPage.pl -template $(TEMPLATE) $< > $@-new mv -f $@-new $@ sales.html: sales.txt aptconvert -toc $@ $<Cherchez comment le fichier doit être mis à jour si Template1.txt a été modifié.
Si une commande est précédée par un '@', elle n'est pas affichée par la commande make :
cible : prerequisite @cc -o target prerequisiteSi une commande commence par un '-', le processus make ne se terminera pas si cette commande génère une erreur (par exemple, effacer un fichier inexistant) :
.PHONY: clean clean: -rm -r $(tempdir)Si vous voulez voir ce qu'effectue une certaine commande de make, e.g. make install mais que vous ne vouliez pas que la commande soit réellement exécutée, utilisez l'option -n au prompt :
wilbert@nutnix:~ > make -n install install -m 755 program /usr/local/bin install -m 644 program.1 /usr/local/man/man1 wilbert@nutnix:~ >
Si vous avez besoin du signe dollar ($) comme partie, par exemple, d'un nom de fichier ou d'une commande shell, utilisez-le doublé ($$):
# Un Makefile # Ne tentez pas ceci chez vous ! :-) source = menu.txt help.txt target: $(source) for i in $(source) ;\ do \ if [ "$$i" = "menu.txt" ] ;\ then \ doThis $$i ;\ else \ doThat $$i ;\ fi ;\ done > targetMake remplacera, avant d'envoyer des commandes au shell pour exécution, ses propres variables et changera le signe double dollar en un seul.
info makeBien sûr, il est possible de lire le Manuel GNU Make avec les navigateurs d'aide GNOME et KDE ou le programme tkinfo.
Liens vers d'autres informations à propos de make:
Amusez-vous bien !