Langue: 日本語 | Español | Français | Português | 中文 | English
Précédent | Suivant | Sommaire | Version originale anglaise (gnu.org)

10 Utilisation des règles implicites

Certaines façons habituelles de refaire des fichiers cibles reviennent très souvent. Par exemple, une manière classique de produire un fichier objet consiste à le générer à partir d'un fichier source C à l'aide du compilateur C cc.

Les règles implicites (implicit rules) servent à indiquer à make comment employer ces techniques habituelles, afin que vous n'ayez pas à les détailler chaque fois que vous voulez les utiliser. Par exemple, il existe une règle implicite pour la compilation C. Ce sont les noms de fichiers qui déterminent quelles règles implicites sont exécutées. Par exemple, la compilation C produit généralement un fichier .o à partir d'un fichier .c. Aussi, lorsque make rencontre cette combinaison de terminaisons de noms de fichiers, il applique la règle implicite de compilation C.

Une chaîne de règles implicites peut s'appliquer en séquence ; par exemple, make refera un fichier .o à partir d'un fichier .y en passant par un fichier .c.

Les règles implicites intégrées utilisent plusieurs variables dans leurs recettes (recipes), si bien qu'en changeant la valeur de ces variables, vous pouvez modifier le comportement de la règle implicite. Par exemple, la variable CFLAGS contrôle les drapeaux passés au compilateur C par la règle implicite de compilation C.

Vous pouvez définir vos propres règles implicites en écrivant des règles de motif (pattern rules).

Les règles de suffixe (suffix rules) constituent une manière plus limitée de définir des règles implicites. Les règles de motif sont plus générales et plus claires, mais les règles de suffixe sont conservées pour des raisons de compatibilité.

10.1 Utiliser les règles implicites

Pour permettre à make de trouver une méthode habituelle de mise à jour d'un fichier cible, il vous suffit de vous abstenir de spécifier vous-même des recettes. Écrivez soit une règle sans recette, soit aucune règle du tout. make déterminera alors quelle règle implicite employer en fonction du type de fichier source qui existe ou qui peut être produit.

Supposons par exemple que le makefile ressemble à ceci :

foo : foo.o bar.o
        cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)

Comme vous mentionnez foo.o sans donner de règle pour ce fichier, make cherche automatiquement une règle implicite indiquant comment le mettre à jour. Cela se produit que le fichier foo.o existe ou non actuellement.

Si une règle implicite est trouvée, elle peut fournir à la fois une recette et un ou plusieurs prérequis (prerequisites) (les fichiers sources). Vous auriez intérêt à écrire une règle sans recette pour foo.o s'il vous fallait spécifier des prérequis supplémentaires — par exemple des fichiers d'en-tête — que la règle implicite ne peut pas fournir.

Chaque règle implicite possède un motif de cible et des motifs de prérequis. Il peut y avoir de nombreuses règles implicites partageant le même motif de cible. Par exemple, de nombreuses règles produisent des fichiers « .o » : l'une à partir d'un fichier « .c » avec le compilateur C ; une autre à partir d'un fichier « .p » avec le compilateur Pascal ; et ainsi de suite. La règle qui s'applique effectivement est celle dont les prérequis existent ou peuvent être produits. Ainsi, si vous avez un fichier foo.c, make exécutera le compilateur C ; sinon, si vous avez un fichier foo.p, make exécutera le compilateur Pascal ; et ainsi de suite.

Bien entendu, lorsque vous écrivez le makefile, vous savez quelle règle implicite vous voulez que make utilise, et vous savez qu'il la choisira parce que vous savez quels fichiers prérequis sont censés exister. Pour un catalogue de toutes les règles implicites prédéfinies, voir Catalogue des règles intégrées.

Nous avons dit plus haut qu'une règle implicite s'applique si les prérequis requis « existent ou peuvent être produits ». Un fichier « peut être produit » s'il est mentionné explicitement dans le makefile comme cible ou comme prérequis, ou si une règle implicite permet de trouver récursivement comment le produire. Lorsqu'un prérequis implicite est le résultat d'une autre règle implicite, on dit qu'il y a chaînage (chaining). Voir Chaînes de règles implicites.

De manière générale, make cherche une règle implicite pour chaque cible, et pour chaque règle à double deux-points, qui n'a pas de recette. Un fichier mentionné uniquement comme prérequis est considéré comme une cible dont la règle ne spécifie rien, de sorte que la recherche de règle implicite a lieu pour lui aussi. Pour le détail du déroulement de cette recherche, voir Algorithme de recherche des règles implicites.

Notez que les prérequis explicites n'influencent pas la recherche de règle implicite. Considérez par exemple cette règle explicite :

foo.o: foo.p

Le prérequis sur foo.p ne signifie pas nécessairement que make refera foo.o selon la règle implicite qui produit un fichier objet, un fichier .o, à partir d'un fichier source Pascal, un fichier .p. Par exemple, si foo.c existe aussi, c'est la règle implicite produisant un fichier objet à partir d'un fichier source C qui sera utilisée, parce qu'elle apparaît avant la règle Pascal dans la liste des règles implicites prédéfinies (voir Catalogue des règles intégrées).

Si vous ne voulez pas qu'une règle implicite soit utilisée pour une cible qui n'a pas de recette, vous pouvez donner à cette cible une recette vide en écrivant un point-virgule (voir Définir des recettes vides).

10.2 Catalogue des règles intégrées

Voici un catalogue des règles implicites prédéfinies, qui sont toujours disponibles à moins que le makefile ne les remplace ou ne les annule explicitement. Pour savoir comment annuler ou remplacer une règle implicite, voir Annuler des règles implicites. L'option « -r » ou « --no-builtin-rules » annule toutes les règles prédéfinies.

Ce manuel ne documente que les règles par défaut disponibles sur les systèmes d'exploitation conformes à POSIX. D'autres systèmes d'exploitation, tels que VMS, Windows, OS/2, etc., peuvent disposer d'ensembles de règles par défaut différents. Pour voir la liste complète des règles et des variables par défaut disponibles dans votre version de GNU make, exécutez « make -p » dans un répertoire sans makefile.

Ces règles ne seront pas toutes définies en permanence, même lorsque l'option « -r » n'est pas donnée. Beaucoup des règles implicites prédéfinies sont implémentées dans make sous forme de règles de suffixe ; aussi, celles qui seront définies dépendent de la liste des suffixes (la liste des prérequis de la cible spéciale .SUFFIXES). La liste des suffixes par défaut est la suivante : .out, .a, .ln, .o, .c, .cc, .C, .cpp, .p, .f, .F, .m, .r, .y, .l, .ym, .lm, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch .web, .sh, .elc, .el. Parmi les règles implicites décrites ci-dessous, toutes celles dont les prérequis portent l'un de ces suffixes sont en réalité des règles de suffixe. Si vous modifiez la liste des suffixes, les seules règles de suffixe prédéfinies encore en vigueur seront celles désignées par un ou deux des suffixes figurant dans la liste que vous spécifiez ; les règles dont les suffixes ne figurent pas dans la liste sont désactivées. Pour tous les détails sur les règles de suffixe, voir Les règles de suffixe à l'ancienne.

Compilation des programmes C

n.o est produit automatiquement à partir de n.c avec une recette de la forme « $(CC) $(CPPFLAGS) $(CFLAGS) -c ».

Compilation des programmes C++

n.o est produit automatiquement à partir de n.cc, n.cpp ou n.C avec une recette de la forme « $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c ». Nous vous encourageons à utiliser le suffixe « .cc » ou « .cpp » plutôt que « .C » pour les fichiers sources C++, afin de mieux prendre en charge les systèmes de fichiers insensibles à la casse.

Compilation des programmes Pascal

n.o est produit automatiquement à partir de n.p avec la recette « $(PC) $(PFLAGS) -c ».

Compilation des programmes Fortran et Ratfor

n.o est produit automatiquement à partir de n.r, n.F ou n.f en exécutant le compilateur Fortran. La recette précise utilisée est la suivante :

« .f »

« $(FC) $(FFLAGS) -c ».

« .F »

« $(FC) $(FFLAGS) $(CPPFLAGS) -c ».

« .r »

« $(FC) $(FFLAGS) $(RFLAGS) -c ».

Prétraitement des programmes Fortran et Ratfor

n.f est produit automatiquement à partir de n.r ou n.F. Cette règle n'exécute que le préprocesseur, pour convertir un programme Ratfor ou un programme Fortran nécessitant un prétraitement en un programme Fortran pur. La recette précise utilisée est la suivante :

« .F »

« $(FC) $(CPPFLAGS) $(FFLAGS) -F ».

« .r »

« $(FC) $(FFLAGS) $(RFLAGS) -F ».

Compilation des programmes Modula-2

n.sym est produit à partir de n.def avec une recette de la forme « $(M2C) $(M2FLAGS) $(DEFFLAGS) ». n.o est produit à partir de n.mod ; sa forme est « $(M2C) $(M2FLAGS) $(MODFLAGS) ».

Assemblage et prétraitement des programmes en assembleur

n.o est produit automatiquement à partir de n.s en exécutant l'assembleur as. La recette précise est « $(AS) $(ASFLAGS) ».

n.s est produit automatiquement à partir de n.S en exécutant le préprocesseur C cpp. La recette précise est « $(CPP) $(CPPFLAGS) ».

Édition de liens d'un seul fichier objet

n est produit automatiquement à partir de n.o en exécutant le compilateur C pour réaliser l'édition de liens du programme. La recette précise utilisée est « $(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS) ».

Cette règle fait ce qu'il faut pour un programme simple ne comportant qu'un seul fichier source. Elle fait aussi ce qu'il faut s'il y a plusieurs fichiers objets (provenant vraisemblablement de divers autres fichiers sources), dont l'un porte un nom correspondant à celui du fichier exécutable. Ainsi,

x: y.o z.o

exécutera, lorsque x.c, y.c et z.c existent tous :

cc -c x.c -o x.o
cc -c y.c -o y.o
cc -c z.c -o z.o
cc x.o y.o z.o -o x
rm -f x.o
rm -f y.o
rm -f z.o

Dans des cas plus compliqués, par exemple lorsqu'il n'existe pas de fichier objet dont le nom dérive du nom du fichier exécutable, vous devez écrire vous-même une recette explicite pour l'édition de liens.

Chaque type de fichier transformé automatiquement en fichier objet « .o » sera lié automatiquement à l'aide du compilateur (« $(CC) », « $(FC) » ou « $(PC) » ; le compilateur C « $(CC) » est utilisé pour assembler les fichiers « .s ») sans l'option « -c ». Cela pourrait se faire en utilisant les fichiers objets « .o » comme fichiers intermédiaires, mais il est plus rapide de réaliser la compilation et l'édition de liens en une seule étape, c'est donc ainsi que cela est fait.

Yacc pour les programmes C

n.c est produit automatiquement à partir de n.y en exécutant Yacc avec la recette « $(YACC) $(YFLAGS) ».

Lex pour les programmes C

n.c est produit automatiquement à partir de n.l en exécutant Lex. La recette effective est « $(LEX) $(LFLAGS) ».

Lex pour les programmes Ratfor

n.r est produit automatiquement à partir de n.l en exécutant Lex. La recette effective est « $(LEX) $(LFLAGS) ».

La convention consistant à utiliser le même suffixe « .l » pour tous les fichiers Lex, qu'ils produisent du code C ou du code Ratfor, fait qu'il est impossible pour make de déterminer automatiquement lequel des deux langages vous employez dans un cas particulier. Lorsqu'on demande à make de refaire un fichier objet à partir d'un fichier « .l », il doit deviner quel compilateur utiliser. Il devine le compilateur C, parce que c'est le cas le plus courant. Si vous utilisez Ratfor, faites en sorte que make le sache en mentionnant n.r dans le makefile. Ou bien, si vous utilisez exclusivement Ratfor, sans aucun fichier C, retirez « .c » de la liste des suffixes des règles implicites de la manière suivante :

.SUFFIXES:
.SUFFIXES: .o .r .f .l …
Création de bibliothèques Lint à partir de programmes C, Yacc ou Lex

n.ln est produit à partir de n.c en exécutant lint. La recette précise est « $(LINT) $(LINTFLAGS) $(CPPFLAGS) -i ». La même recette est utilisée sur le code C produit à partir de n.y ou n.l.

TeX et Web

n.dvi est produit à partir de n.tex avec la recette « $(TEX) ». n.tex est produit à partir de n.web avec « $(WEAVE) », ou à partir de n.w (et de n.ch s'il existe ou peut être produit) avec « $(CWEAVE) ». n.p est produit à partir de n.web avec « $(TANGLE) », et n.c est produit à partir de n.w (et de n.ch s'il existe ou peut être produit) avec « $(CTANGLE) ».

Texinfo et Info

n.dvi est produit à partir de n.texinfo, n.texi ou n.txinfo avec la recette « $(TEXI2DVI) $(TEXI2DVI_FLAGS) ». n.info est produit à partir de n.texinfo, n.texi ou n.txinfo avec la recette « $(MAKEINFO) $(MAKEINFO_FLAGS) ».

RCS

Tout fichier n est extrait si nécessaire d'un fichier RCS nommé soit n,v, soit RCS/n,v. La recette précise utilisée est « $(CO) $(COFLAGS) ». n ne sera pas extrait de RCS s'il existe déjà, même si le fichier RCS est plus récent. Les règles pour RCS sont terminales (terminal) (voir Règles de motif à correspondance universelle), si bien que les fichiers RCS ne peuvent pas être engendrés à partir d'une autre source ; ils doivent effectivement exister.

SCCS

Tout fichier n est extrait si nécessaire d'un fichier SCCS nommé soit s.n, soit SCCS/s.n. La recette précise utilisée est « $(GET) $(GFLAGS) ». Les règles pour SCCS sont terminales (terminal) (voir Règles de motif à correspondance universelle), si bien que les fichiers SCCS ne peuvent pas être engendrés à partir d'une autre source ; ils doivent effectivement exister.

Pour les besoins de SCCS, un fichier n est copié depuis n.sh et rendu exécutable (pour tout le monde). Cela est destiné aux scripts shell archivés dans SCCS. Comme RCS préserve les permissions d'exécution d'un fichier, vous n'avez pas besoin d'utiliser cette fonctionnalité avec RCS.

Nous vous recommandons d'éviter d'utiliser SCCS. RCS est largement reconnu comme supérieur, et il est en outre libre. En choisissant des logiciels libres à la place de logiciels propriétaires comparables (ou inférieurs), vous soutenez le mouvement du logiciel libre.

En général, vous ne voudrez modifier que les variables énumérées dans le tableau ci-dessus, qui sont décrites dans la section suivante.

Cependant, les recettes des règles implicites intégrées utilisent en réalité des variables telles que COMPILE.c, LINK.p et PREPROCESS.S, dont les valeurs contiennent les recettes énumérées ci-dessus.

make suit la convention selon laquelle la règle qui compile un fichier source .x utilise la variable COMPILE.x. De même, la règle qui produit un exécutable à partir d'un fichier .x utilise LINK.x ; et la règle qui prétraite un fichier .x utilise PREPROCESS.x.

Toute règle qui produit un fichier objet utilise la variable OUTPUT_OPTION. make définit cette variable soit de manière à contenir « -o $@ », soit comme vide, selon une option déterminée à la compilation. Vous avez besoin de l'option « -o » pour garantir que la sortie aille dans le bon fichier lorsque le fichier source se trouve dans un répertoire différent, comme lors de l'utilisation de VPATH (voir Recherche dans les répertoires des prérequis). Cependant, sur certains systèmes, les compilateurs n'acceptent pas l'option « -o » pour les fichiers objets. Si vous utilisez un tel système et que vous employez VPATH, certaines compilations placeront leur sortie au mauvais endroit. Un contournement possible de ce problème consiste à donner à OUTPUT_OPTION la valeur « ; mv $*.o $@ ».

10.3 Variables utilisées par les règles implicites

Les recettes des règles implicites intégrées font un usage abondant de certaines variables prédéfinies. Vous pouvez modifier la valeur de ces variables dans le makefile, au moyen d'arguments passés à make, ou dans l'environnement, afin de changer le comportement des règles implicites sans avoir à redéfinir les règles elles-mêmes. Vous pouvez annuler toutes les variables utilisées par les règles implicites avec l'option « -R » ou « --no-builtin-variables ».

Par exemple, la recette utilisée pour compiler un fichier source C dit en réalité « $(CC) -c $(CFLAGS) $(CPPFLAGS) ». Les valeurs par défaut des variables utilisées sont « cc » et la chaîne vide, ce qui aboutit à la commande « cc -c ». En redéfinissant « CC » en « ncc », vous pourriez faire en sorte que « ncc » soit utilisé pour toutes les compilations C effectuées par la règle implicite. En redéfinissant « CFLAGS » en « -g », vous pourriez passer l'option « -g » à chaque compilation. Toutes les règles implicites qui réalisent une compilation C utilisent « $(CC) » pour obtenir le nom du programme compilateur, et toutes incluent « $(CFLAGS) » parmi les arguments donnés au compilateur.

Les variables utilisées dans les règles implicites se répartissent en deux catégories : celles qui sont des noms de programmes (comme CC) et celles qui contiennent des arguments pour les programmes (comme CFLAGS). (Le « nom d'un programme » peut lui aussi contenir quelques arguments de commande, mais il doit commencer par le nom d'un véritable programme exécutable.) Si la valeur d'une variable contient plus d'un argument, séparez-les par des espaces.

Les tableaux suivants décrivent quelques-unes des variables prédéfinies les plus couramment utilisées. Cette liste n'est pas exhaustive, et les valeurs par défaut indiquées ici ne sont peut-être pas celles que make retiendra dans votre environnement. Pour voir la liste complète des variables prédéfinies de votre instance de GNU make, vous pouvez exécuter « make -p » dans un répertoire sans makefile.

Voici un tableau de quelques-unes des variables les plus courantes utilisées comme noms de programmes dans les règles intégrées :

AR

Programme de gestion d'archives ; par défaut « ar ».

AS

Programme de compilation des fichiers en assembleur ; par défaut « as ».

CC

Programme de compilation des programmes C ; par défaut « cc ».

CXX

Programme de compilation des programmes C++ ; par défaut « g++ ».

CPP

Programme exécutant le préprocesseur C, avec les résultats sur la sortie standard ; par défaut « $(CC) -E ».

FC

Programme de compilation ou de prétraitement des programmes Fortran et Ratfor ; par défaut « f77 ».

M2C

Programme à utiliser pour compiler le code source Modula-2 ; par défaut « m2c ».

PC

Programme de compilation des programmes Pascal ; par défaut « pc ».

CO

Programme d'extraction d'un fichier depuis RCS ; par défaut « co ».

GET

Programme d'extraction d'un fichier depuis SCCS ; par défaut « get ».

LEX

Programme à utiliser pour transformer des grammaires Lex en code source ; par défaut « lex ».

YACC

Programme à utiliser pour transformer des grammaires Yacc en code source ; par défaut « yacc ».

LINT

Programme à utiliser pour exécuter lint sur le code source ; par défaut « lint ».

MAKEINFO

Programme de conversion d'un fichier source Texinfo en fichier Info ; par défaut « makeinfo ».

TEX

Programme de production de fichiers DVI TeX à partir de sources TeX ; par défaut « tex ».

TEXI2DVI

Programme de production de fichiers DVI TeX à partir de sources Texinfo ; par défaut « texi2dvi ».

WEAVE

Programme de conversion de Web en TeX ; par défaut « weave ».

CWEAVE

Programme de conversion de C Web en TeX ; par défaut « cweave ».

TANGLE

Programme de conversion de Web en Pascal ; par défaut « tangle ».

CTANGLE

Programme de conversion de C Web en C ; par défaut « ctangle ».

RM

Commande de suppression d'un fichier ; par défaut « rm -f ».

Voici un tableau de variables dont les valeurs constituent des arguments supplémentaires pour les programmes ci-dessus. La valeur par défaut de toutes ces variables est la chaîne vide, sauf indication contraire.

ARFLAGS

Drapeaux à donner au programme de gestion d'archives ; par défaut « rv ».

ASFLAGS

Drapeaux supplémentaires à donner à l'assembleur (lorsqu'il est invoqué explicitement sur un fichier « .s » ou « .S »).

CFLAGS

Drapeaux supplémentaires à donner au compilateur C.

CXXFLAGS

Drapeaux supplémentaires à donner au compilateur C++.

COFLAGS

Drapeaux supplémentaires à donner au programme co de RCS.

CPPFLAGS

Drapeaux supplémentaires à donner au préprocesseur C et aux programmes qui l'utilisent (les compilateurs C et Fortran).

FFLAGS

Drapeaux supplémentaires à donner au compilateur Fortran.

GFLAGS

Drapeaux supplémentaires à donner au programme get de SCCS.

LDFLAGS

Drapeaux supplémentaires à donner aux compilateurs lorsqu'ils sont censés invoquer l'éditeur de liens « ld », par exemple -L. Les bibliothèques (-lfoo) devraient plutôt être ajoutées à la variable LDLIBS.

LDLIBS

Drapeaux ou noms de bibliothèques donnés aux compilateurs lorsqu'ils sont censés invoquer l'éditeur de liens « ld ». LOADLIBES est une variante déconseillée (mais toujours prise en charge) de LDLIBS. Les drapeaux d'édition de liens autres que des bibliothèques, comme -L, devraient figurer dans la variable LDFLAGS.

LFLAGS

Drapeaux supplémentaires à donner à Lex.

YFLAGS

Drapeaux supplémentaires à donner à Yacc.

PFLAGS

Drapeaux supplémentaires à donner au compilateur Pascal.

RFLAGS

Drapeaux supplémentaires à donner au compilateur Fortran pour les programmes Ratfor.

LINTFLAGS

Drapeaux supplémentaires à donner à lint.

10.4 Chaînes de règles implicites

Il arrive qu'un fichier puisse être produit par une succession de règles implicites. Par exemple, le fichier n.o peut être produit à partir de n.y en exécutant d'abord Yacc, puis cc. Une telle succession est appelée une chaîne (chain).

Si le fichier n.c existe, ou s'il est mentionné dans le makefile, aucune recherche particulière n'est nécessaire : make constate que le fichier objet peut être produit par compilation C à partir de n.c ; plus tard, lorsqu'il examine comment produire n.c, la règle qui exécute Yacc est utilisée. Au bout du compte, n.c et n.o sont tous deux mis à jour.

Toutefois, même si n.c n'existe pas et n'est pas mentionné, make sait l'imaginer comme le maillon manquant entre n.o et n.y ! Dans ce cas, n.c est appelé un fichier intermédiaire (intermediate file). Une fois que make a décidé d'utiliser le fichier intermédiaire, celui-ci est inscrit dans la base de données comme s'il avait été mentionné dans le makefile, accompagné de la règle implicite indiquant comment le créer.

Les fichiers intermédiaires sont refaits à l'aide de leurs règles, comme tous les autres fichiers. Mais les fichiers intermédiaires sont traités différemment de deux manières.

La première différence concerne ce qui se passe lorsque le fichier intermédiaire n'existe pas. Si un fichier ordinaire b n'existe pas et que make examine une cible qui dépend de b, make crée invariablement b, puis met à jour la cible à partir de b. Mais si b est un fichier intermédiaire, alors make peut s'en abstenir : il ne créera pas b à moins que l'un de ses prérequis ne soit périmé. Cela signifie que la cible dépendant de b ne sera pas reconstruite non plus, à moins qu'il n'existe une autre raison de mettre cette cible à jour — par exemple, la cible n'existe pas, ou un autre prérequis est plus récent que la cible.

La seconde différence est que si make crée effectivement b afin de mettre à jour autre chose, il supprime b par la suite, une fois qu'il n'en a plus besoin. Par conséquent, un fichier intermédiaire qui n'existait pas avant make n'existe pas non plus après make. make vous informe de cette suppression en affichant une commande « rm » indiquant quel fichier il supprime.

Vous pouvez marquer explicitement un fichier comme intermédiaire en l'énumérant comme prérequis de la cible spéciale .INTERMEDIATE. Cela prend effet même si le fichier est mentionné explicitement d'une autre manière.

Un fichier ne peut pas être intermédiaire s'il est mentionné dans le makefile comme cible ou comme prérequis ; aussi, une façon d'éviter la suppression des fichiers intermédiaires est de les ajouter comme prérequis d'une cible quelconque. Cependant, procéder ainsi peut conduire make à effectuer un travail supplémentaire lors de la recherche des règles de motif (voir Algorithme de recherche des règles implicites).

Une autre solution consiste à énumérer un fichier comme prérequis de la cible spéciale .NOTINTERMEDIATE, ce qui force ce fichier à ne pas être considéré comme intermédiaire (tout comme le ferait toute autre mention du fichier). De plus, énumérer le motif de cible d'une règle de motif comme prérequis de .NOTINTERMEDIATE garantit qu'aucune des cibles engendrées par cette règle de motif n'est considérée comme intermédiaire.

Vous pouvez désactiver complètement les fichiers intermédiaires dans votre makefile en fournissant .NOTINTERMEDIATE comme cible sans prérequis : dans ce cas, cela s'applique à tous les fichiers du makefile.

Si vous ne voulez pas que make crée un fichier simplement parce qu'il n'existe pas encore, mais que vous ne voulez pas non plus que make supprime automatiquement ce fichier, vous pouvez le marquer comme fichier secondaire (secondary). Pour cela, énumérez-le comme prérequis de la cible spéciale .SECONDARY. Marquer un fichier comme secondaire le marque également comme intermédiaire.

Une chaîne peut faire intervenir plus de deux règles implicites. Par exemple, il est possible de produire un fichier foo à partir de RCS/foo.y,v en exécutant RCS, Yacc et cc. Dans ce cas, foo.y et foo.c sont tous deux des fichiers intermédiaires qui sont supprimés à la fin.

Aucune règle implicite ne peut apparaître plus d'une fois dans une chaîne. Cela signifie que make n'envisagera même pas une chose aussi absurde que de produire foo à partir de foo.o.o en exécutant deux fois l'éditeur de liens. Cette contrainte a en outre l'avantage d'empêcher toute boucle infinie dans la recherche d'une chaîne de règles implicites.

Il existe quelques règles implicites spéciales destinées à optimiser certains cas qui seraient sinon traités par des chaînes de règles. Par exemple, produire foo à partir de foo.c pourrait être traité en compilant et en liant au moyen de règles chaînées distinctes, en utilisant foo.o comme fichier intermédiaire. Mais ce qui se passe en réalité, c'est qu'une règle spéciale dédiée à ce cas réalise la compilation et l'édition de liens avec une seule commande cc. La règle optimisée est utilisée de préférence à la chaîne étape par étape parce qu'elle apparaît plus tôt dans l'ordre des règles.

Enfin, pour des raisons de performance, make n'envisage pas les règles non terminales à correspondance universelle (c'est-à-dire « %: ») lorsqu'il cherche une règle pour produire le prérequis d'une règle implicite (voir Règles de motif à correspondance universelle).

10.5 Définir et redéfinir des règles de motif

Vous définissez une règle implicite en écrivant une règle de motif (pattern rule). Une règle de motif ressemble à une règle ordinaire, à ceci près que sa cible contient le caractère « % » (exactement un). La cible est traitée comme un motif servant à apparier des noms de fichiers ; le « % » correspond à n'importe quelle sous-chaîne non vide, tandis que les autres caractères ne correspondent qu'à eux-mêmes. Les prérequis utilisent de même « % » pour indiquer comment leur nom se rattache au nom de la cible.

Ainsi, la règle de motif « %.o : %.c » indique comment produire n'importe quel fichier stem.o à partir d'un autre fichier stem.c.

Notez que l'expansion utilisant « % » dans les règles de motif a lieu après toute expansion de variable ou de fonction, lesquelles se produisent au moment où le makefile est lu. Voir Comment utiliser les variables et Fonctions de transformation de texte.

10.5.1 Introduction aux règles de motif

Une règle de motif contient le caractère « % » (exactement un) dans la cible ; pour le reste, elle ressemble exactement à une règle ordinaire. La cible est un motif servant à apparier des noms de fichiers ; le « % » correspond à n'importe quelle sous-chaîne non vide, tandis que les autres caractères ne correspondent qu'à eux-mêmes.

Par exemple, « %.c » en tant que motif correspond à tout nom de fichier se terminant par « .c ». « s.%.c » en tant que motif correspond à tout nom de fichier qui commence par « s. », se termine par « .c » et comporte au moins cinq caractères. (Il doit y avoir au moins un caractère pour correspondre au « % ».) La sous-chaîne à laquelle le « % » correspond est appelée le radical (stem).

Le « % » dans un prérequis d'une règle de motif représente le même radical que celui auquel le « % » de la cible a correspondu. Pour qu'une règle de motif s'applique, son motif de cible doit correspondre au nom de fichier examiné et tous ses prérequis (après substitution du motif) doivent désigner des fichiers qui existent ou peuvent être produits. Ces fichiers deviennent les prérequis de la cible.

Ainsi, une règle de la forme

%.o : %.c ; recipe

indique comment produire un fichier n.o, avec un autre fichier n.c comme prérequis, à condition que n.c existe ou puisse être produit.

Il peut aussi y avoir des prérequis qui n'utilisent pas « % » ; un tel prérequis se rattache à chaque fichier produit par cette règle de motif. Ces prérequis invariables sont parfois utiles.

Une règle de motif n'a pas besoin d'avoir des prérequis contenant « % », ni même, en fait, aucun prérequis du tout. Une telle règle est en pratique un caractère générique généralisé. Elle fournit un moyen de produire n'importe quel fichier correspondant au motif de cible. Voir Définir des règles par défaut de dernier recours.

Plusieurs règles de motif peuvent correspondre à une même cible. Dans ce cas, make choisit la règle qui « convient le mieux ». Voir Comment les motifs correspondent.

Les règles de motif peuvent avoir plusieurs cibles ; cependant, chaque cible doit contenir un caractère %. Les multiples motifs de cible des règles de motif sont toujours traités comme des cibles groupées (voir Cibles multiples dans une règle), qu'ils utilisent le séparateur : ou &:.

Il existe toutefois une exception. Si une cible de motif est périmée ou inexistante alors que le makefile n'a pas besoin de la construire, cette cible n'est pas une raison de considérer les autres cibles comme périmées. Notez que cette exception historique est appelée à disparaître dans une future version de GNU make, vous ne devriez donc pas vous y fier. Lorsque make détecte cette situation, il émet l'avertissement pattern recipe did not update peer target (la recette de motif n'a pas mis à jour la cible associée). Cependant, make ne peut pas détecter toutes ces situations. Veillez à ce que la recette mette toujours à jour tous les motifs de cible lorsqu'elle est exécutée.

10.5.2 Exemples de règles de motif

Voici quelques exemples de règles de motif effectivement prédéfinies dans make. D'abord, la règle qui compile les fichiers « .c » en fichiers « .o » :

%.o : %.c
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

Elle définit une règle permettant de produire n'importe quel fichier x.o à partir de x.c. Cette recette utilise les variables automatiques « $@ » et « $< » pour substituer, dans chaque cas où la règle s'applique, le nom du fichier cible et le nom du fichier source (voir Variables automatiques).

Voici une deuxième règle intégrée :

% :: RCS/%,v
        $(CO) $(COFLAGS) $<

Elle définit une règle permettant de produire n'importe quel fichier x à partir du fichier correspondant x,v situé dans le sous-répertoire RCS. Comme la cible est « % », cette règle s'applique à n'importe quel fichier, pourvu que le fichier prérequis approprié existe. Le double deux-points rend cette règle terminale (terminal) ; cela signifie que son prérequis ne doit pas être un fichier intermédiaire (voir Règles de motif à correspondance universelle).

Cette règle de motif a deux cibles :

%.tab.c %.tab.h: %.y
        bison -d $<

Elle indique à make que la recette « bison -d x.y » produit à la fois x.tab.c et x.tab.h. Si le fichier foo dépend des fichiers parse.tab.o et scan.o, et que par ailleurs le fichier scan.o dépend du fichier parse.tab.h, alors, lorsque parse.y est modifié, la recette « bison -d parse.y » n'est exécutée qu'une seule fois, et les prérequis de parse.tab.o comme de scan.o sont satisfaits. (Vraisemblablement, le fichier parse.tab.o sera recompilé à partir de parse.tab.c et le fichier scan.o à partir de scan.c, tandis que foo sera lié à partir de parse.tab.o, scan.o et de ses autres prérequis, et il continuera heureusement de fonctionner par la suite.)

10.5.3 Variables automatiques

Supposons que vous écriviez une règle de motif pour compiler un fichier « .c » en fichier « .o ». Comment écrire la commande « cc » pour qu'elle agisse sur le bon nom de fichier source ? Vous ne pouvez pas écrire ce nom dans la recette, car il diffère à chaque fois que la règle implicite s'applique.

C'est là qu'interviennent les variables automatiques (automatic variables), une fonctionnalité spéciale de make. La valeur de ces variables est recalculée à chaque fois, pour chaque règle exécutée, à partir de la cible et des prérequis de cette règle. Dans cet exemple, vous emploierez « $@ » pour le nom du fichier objet et « $< » pour le nom du fichier source.

Il est très important de bien comprendre que la portée dans laquelle la valeur des variables automatiques est disponible est limitée. Ces valeurs n'existent que dans la recette. En particulier, vous ne pouvez les utiliser nulle part dans la liste des cibles d'une règle ; elles n'y ont pas de valeur et s'y développent en chaîne vide. De même, vous ne pouvez pas y accéder directement dans la liste des prérequis d'une règle. Une erreur courante consiste à essayer d'utiliser $@ dans la liste des prérequis ; cela ne fonctionne pas. Toutefois, GNU make dispose d'une fonctionnalité spéciale, l'expansion secondaire (voir Expansion secondaire), qui vous permet d'utiliser la valeur des variables automatiques dans la liste des prérequis.

Voici un tableau des variables automatiques :

$@

Le nom du fichier de la cible de la règle. Si la cible est un membre d'archive, « $@ » est le nom du fichier d'archive. Dans une règle de motif comportant plusieurs cibles (voir Introduction aux règles de motif), « $@ » est le nom de la cible qui a provoqué l'exécution de la recette de la règle.

$%

Le nom de membre de la cible, lorsque la cible est un membre d'archive. Voir Mettre à jour des fichiers d'archive avec make. Par exemple, si la cible est foo.a(bar.o), alors « $% » vaut bar.o et « $@ » vaut foo.a. Lorsque la cible n'est pas un membre d'archive, « $% » est vide.

$<

Le nom du premier prérequis. Si la cible a obtenu sa recette d'une règle implicite, il s'agit du premier prérequis ajouté par la règle implicite (voir Utilisation des règles implicites).

$?

Les noms de tous les prérequis plus récents que la cible, séparés par des espaces. Si la cible n'existe pas, tous les prérequis sont inclus. Pour les prérequis qui sont des membres d'archive, seul le membre désigné est utilisé (voir Mettre à jour des fichiers d'archive avec make).

« $? » est également utile dans les règles explicites lorsque vous voulez n'opérer que sur les prérequis modifiés. Supposons par exemple qu'une archive nommée lib soit censée contenir des copies de plusieurs fichiers objets. La règle suivante copie dans l'archive uniquement les fichiers objets modifiés :

lib: foo.o bar.o lose.o win.o
        ar r lib $?
$^

Les noms de tous les prérequis, séparés par des espaces. Pour les prérequis qui sont des membres d'archive, seul le membre désigné est utilisé (voir Mettre à jour des fichiers d'archive avec make). Une cible n'a qu'un seul prérequis pour chaque fichier dont elle dépend, peu importe combien de fois ce même fichier est énuméré comme prérequis. Aussi, même si vous énumérez plusieurs fois le même prérequis pour une cible, la valeur de $^ ne contient qu'une seule copie de ce nom. Cette liste n'inclut pas les prérequis exclusivement d'ordre ; pour ceux-ci, voir la variable « $| » ci-dessous.

$+

Ceci ressemble à « $^ », mais les prérequis énumérés plusieurs fois sont inclus avec leurs doublons, dans l'ordre où ils sont énumérés dans le makefile. C'est surtout utile dans les commandes d'édition de liens, où il est parfois pertinent de répéter des noms de fichiers de bibliothèques dans un ordre particulier.

$|

Les noms de tous les prérequis exclusivement d'ordre, séparés par des espaces.

$*

Le radical avec lequel une règle implicite a établi la correspondance (voir Comment les motifs correspondent). Si la cible est dir/a.foo.b et que le motif de cible est a.%.b, alors le radical est dir/foo. Le radical est utile pour construire les noms de fichiers apparentés.

Dans les règles de motif statiques, le radical est la partie du nom de fichier à laquelle le « % » du motif de cible a correspondu.

Les règles explicites n'ont pas de radical, de sorte que « $* » ne peut pas être déterminé de cette manière. À la place, si le nom de la cible se termine par un suffixe reconnu (voir Les règles de suffixe à l'ancienne), « $* » prend la valeur du nom de la cible auquel ce suffixe a été retiré. Par exemple, si le nom de la cible est « foo.c », alors, « .c » étant un suffixe, « $* » prend la valeur « foo ». Si GNU make fait cette chose étrange, c'est uniquement pour assurer la compatibilité avec d'autres implémentations de make. En général, vous devriez éviter d'utiliser « $* » ailleurs que dans les règles implicites ou les règles de motif statiques.

Si, dans une règle explicite, le nom de la cible ne se termine pas par un suffixe reconnu, « $* » prend la valeur de la chaîne vide pour cette règle.

Parmi les variables énumérées ci-dessus, quatre ont pour valeur un seul nom de fichier, et trois ont pour valeur une liste de noms de fichiers. Ces sept variables possèdent des variantes qui extraient seulement la partie répertoire d'un fichier, ou seulement le nom du fichier au sein du répertoire. Le nom de ces variantes se forme en ajoutant respectivement « D » ou « F » à la fin. On obtient un effet semblable avec les fonctions dir et notdir (voir Fonctions pour les noms de fichiers). Notez toutefois que toutes les variantes « D » omettent la barre oblique finale ; la sortie de la fonction dir comporte toujours une barre oblique finale. Voici un tableau des variantes :

« $(@D) »

La partie répertoire du nom de fichier de la cible, sa barre oblique finale retirée. Si la valeur de « $@ » est dir/foo.o, alors « $(@D) » est dir. Si « $@ » ne contient pas de barre oblique, cette valeur est ..

« $(@F) »

La partie nom de fichier au sein du répertoire, du nom de fichier de la cible. Si la valeur de « $@ » est dir/foo.o, alors « $(@F) » est foo.o. « $(@F) » est équivalent à « $(notdir $@) ».

« $(*D) »
« $(*F) »

La partie répertoire et la partie nom de fichier au sein du répertoire, du radical. Dans cet exemple, ce sont dir et foo.

« $(%D) »
« $(%F) »

La partie répertoire et la partie nom de fichier au sein du répertoire, du nom de membre d'archive de la cible. Cela n'a de sens que pour les cibles de membre d'archive de la forme archive(member), et n'est utile que lorsque member peut contenir un nom de répertoire. (Voir Les membres d'archive comme cibles.)

« $(<D) »
« $(<F) »

La partie répertoire et la partie nom de fichier au sein du répertoire, du premier prérequis.

« $(^D) »
« $(^F) »

La liste des parties répertoire et la liste des parties nom de fichier au sein du répertoire, de tous les prérequis.

« $(+D) »
« $(+F) »

La liste des parties répertoire et la liste des parties nom de fichier au sein du répertoire, de tous les prérequis, doublons inclus pour les prérequis répétés.

« $(?D) »
« $(?F) »

La liste des parties répertoire et la liste des parties nom de fichier au sein du répertoire, de tous les prérequis plus récents que la cible.

Notez que, pour parler de ces variables automatiques, nous employons une convention stylistique particulière. Plutôt que d'écrire « la variable < », comme nous le ferions pour une variable ordinaire telle que objects ou CFLAGS, nous écrivons « la valeur de « $< » », parce que, dans ce cas particulier, nous estimons que cette convention paraît plus naturelle. N'y voyez pas un sens profond. « $< » désigne simplement la variable nommée <, tout comme « $(CFLAGS) » désigne la variable nommée CFLAGS. Écrire « $(<) » au lieu de « $< » revient exactement au même.

10.5.4 Comment les motifs correspondent

Un motif de cible se compose d'un « % » placé entre un préfixe et un suffixe. Le préfixe ou le suffixe, ou les deux, peuvent être vides. Un motif correspond à un nom de fichier seulement si ce nom commence par le préfixe et se termine par le suffixe, sans que les deux se chevauchent. Le texte situé entre le préfixe et le suffixe est appelé le radical (stem). Ainsi, lorsque le motif « %.o » correspond au nom de fichier test.o, le radical est « test ». Les prérequis d'une règle de motif sont convertis en noms de fichiers réels en remplaçant le caractère « % » par le radical. Ainsi, dans le même exemple, si l'un des prérequis est écrit « %.c », il se développe en « test.c ».

Lorsque le motif de cible ne contient pas de barre oblique (ce qui est habituellement le cas), les noms de répertoire présents dans le nom de fichier sont retirés du nom de fichier avant qu'il ne soit comparé au préfixe et au suffixe de la cible. Après la comparaison du nom de fichier avec le motif de cible, le nom de répertoire, accompagné de la barre oblique qui le termine, est ajouté en tête des noms de fichiers prérequis engendrés à partir des motifs de prérequis de la règle de motif et du nom de fichier. Les répertoires ne sont ignorés que dans le but de trouver la règle implicite à utiliser, et non lors de l'application de cette règle. Ainsi, « e%t » correspond au nom de fichier src/eat, avec le radical « src/a ». Lorsque les prérequis sont convertis en noms de fichiers, le répertoire issu du radical est ajouté en tête, tandis que le reste du radical remplace le « % ». Le radical « src/a » et le motif de prérequis « c%r » donnent le nom de fichier src/car.

Une règle de motif ne peut servir à construire un fichier que si son motif de cible correspond au nom de ce fichier et si tous les prérequis de cette règle existent ou peuvent être construits. Les règles que vous écrivez ont la priorité sur les règles intégrées. Notez toutefois qu'une règle qui peut être satisfaite sans chaîner d'autres règles implicites (par exemple, une règle sans prérequis, ou dont les prérequis existent déjà ou sont déjà mentionnés) a toujours la priorité sur une règle dont les prérequis doivent être produits en chaînant d'autres règles implicites.

Il peut arriver que deux règles de motif ou plus satisfassent ces critères. Dans ce cas, make choisit la règle dont le radical est le plus court (c'est-à-dire le motif correspondant de la manière la plus spécifique). Si plusieurs règles de motif ont le radical le plus court, make choisit la première trouvée dans le makefile.

Cet algorithme a pour conséquence de privilégier les règles plus spécifiques par rapport aux règles plus générales. Par exemple :

%.o: %.c
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

%.o : %.f
        $(COMPILE.F) $(OUTPUT_OPTION) $<

lib/%.o: lib/%.c
        $(CC) -fPIC -c $(CFLAGS) $(CPPFLAGS) $< -o $@

Étant données ces règles, lorsqu'on demande de construire bar.o alors que bar.c et bar.f existent tous deux, make choisit la première règle et compile bar.c en bar.o. Dans la même situation, si bar.c n'existe pas, make choisit la deuxième règle et compile bar.f en bar.o.

Lorsqu'on demande à make de construire lib/bar.o et que lib/bar.c et lib/bar.f existent tous deux, c'est la troisième règle qui est choisie, parce que le radical de cette règle (« bar ») est plus court que celui de la première règle (« lib/bar »). Si lib/bar.c n'existe pas, la troisième règle n'est plus éligible et c'est la deuxième règle qui est utilisée, même si son radical est plus long.

10.5.5 Règles de motif à correspondance universelle

Lorsque la cible d'une règle de motif est un simple « % », elle correspond à n'importe quel nom de fichier. Nous appelons de telles règles des règles à correspondance universelle (match-anything). Elles sont extrêmement utiles, mais leur examen peut prendre beaucoup de temps à make, car il doit examiner toutes ces règles pour chaque nom de fichier énuméré comme cible ou comme prérequis.

Supposons que le makefile mentionne foo.c. Pour cette cible, make devrait envisager de la produire en liant le fichier objet foo.c.o, ou en compilant et liant le C à partir de foo.c.c en une seule étape, ou en compilant et liant le Pascal à partir de foo.c.p, ainsi que beaucoup d'autres possibilités encore.

Nous savons, nous, que ces possibilités sont absurdes, parce que foo.c est un fichier source C et non un fichier exécutable. Même si make examinait ces possibilités, il finirait par les écarter, puisque des fichiers tels que foo.c.o ou foo.c.p n'existent pas. Mais ces possibilités sont si nombreuses que, si make devait les examiner, il deviendrait très lent.

Pour accélérer les choses, nous avons imposé diverses contraintes à la façon dont make examine les règles à correspondance universelle. Deux types de contraintes sont applicables, et chaque fois que vous définissez une règle à correspondance universelle, vous devez choisir l'une ou l'autre pour cette règle.

Une possibilité consiste à désigner la règle à correspondance universelle comme terminale (terminal) en la définissant avec un double deux-points. Lorsqu'une règle est terminale, elle ne s'applique que si son prérequis existe réellement ; il ne suffit pas qu'il puisse être produit par une autre règle implicite. Autrement dit, aucun chaînage supplémentaire n'est autorisé au-delà d'une règle terminale.

Par exemple, les règles implicites intégrées qui extraient des sources de fichiers RCS ou SCCS sont terminales ; il en résulte que, si le fichier foo.c,v n'existe pas, make n'envisagera même pas de le produire comme fichier intermédiaire à partir de foo.c,v.o ou RCS/SCCS/s.foo.c,v. Les fichiers RCS et SCCS sont en général des fichiers sources ultimes, qui ne devraient être refaits à partir d'aucun autre fichier. make peut donc gagner du temps en ne cherchant pas comment les refaire.

Si vous ne désignez pas une règle à correspondance universelle comme terminale, elle est non terminale. Une règle non terminale à correspondance universelle ne peut pas s'appliquer au prérequis d'une règle implicite, ni à un nom de fichier qui désigne un type particulier de données. On dit qu'un nom de fichier désigne un type particulier de données lorsqu'il correspond à la cible d'une règle implicite qui n'est pas à correspondance universelle.

Par exemple, le nom de fichier foo.c correspond à la cible de la règle de motif « %.c : %.y » (la règle qui exécute Yacc). Que cette règle soit réellement applicable ou non (ce qui n'arrive que s'il existe un fichier foo.y), le seul fait que sa cible corresponde suffit à empêcher qu'une règle non terminale à correspondance universelle soit envisagée pour le fichier foo.c. make n'envisage donc même pas de produire foo.c comme fichier exécutable à partir de foo.c.o, foo.c.c, foo.c.p, etc.

La motivation de cette restriction est la suivante : les règles non terminales à correspondance universelle servent à produire des fichiers contenant un type particulier de données (comme les fichiers exécutables), alors qu'un nom de fichier portant un suffixe reconnu désigne un autre type particulier de données (comme un fichier source C).

Pour reconnaître certains noms de fichiers et éviter ainsi qu'une règle non terminale à correspondance universelle ne soit envisagée, des règles de motif factices spéciales et intégrées sont prévues. Ces règles factices n'ont ni prérequis ni recette, et elles sont ignorées à toute autre fin. Par exemple, la règle implicite intégrée suivante

%.p :

existe pour faire en sorte qu'un fichier source Pascal tel que foo.p corresponde à un motif de cible donné, et empêcher ainsi qu'on perde du temps à chercher foo.p.o ou foo.p.c.

Des règles de motif factices comme celle pour « %.p » sont créées pour tous les suffixes énumérés comme utilisables dans des règles de suffixe (voir Les règles de suffixe à l'ancienne).

10.5.6 Annuler des règles implicites

Vous pouvez remplacer une règle implicite intégrée (ou une règle que vous avez vous-même définie) en définissant une nouvelle règle de motif ayant la même cible et les mêmes prérequis, mais une recette différente. Lorsque la nouvelle règle est définie, elle remplace la règle intégrée. La position de la nouvelle règle dans l'ordre des règles implicites est déterminée par l'endroit où vous l'avez écrite.

Vous pouvez annuler une règle implicite intégrée en définissant une règle de motif ayant la même cible et les mêmes prérequis, mais sans recette. Par exemple, ce qui suit annule la règle qui exécute l'assembleur :

%.o : %.s

10.6 Définir des règles par défaut de dernier recours

Vous pouvez définir une règle implicite de dernier recours en écrivant une règle de motif terminale à correspondance universelle, sans prérequis (voir Règles de motif à correspondance universelle). Elle est tout à fait identique à n'importe quelle autre règle de motif ; sa seule particularité est qu'elle correspond à n'importe quelle cible. Ainsi, la recette d'une telle règle est utilisée pour toutes les cibles et tous les prérequis qui n'ont pas de recette propre et auxquels aucune autre règle implicite ne s'applique.

Par exemple, lorsque vous testez un makefile, il peut vous arriver de ne pas vous soucier de savoir si les fichiers sources contiennent des données réelles, mais seulement qu'ils existent. Dans un tel cas, vous pouvez faire ceci :

%::
        touch $@

Cela permet de produire automatiquement tous les fichiers sources nécessaires (en tant que prérequis).

Vous pouvez aussi définir une recette à utiliser pour les cibles qui n'ont aucune règle — y compris celles dont aucune recette n'est spécifiée. Pour cela, vous écrivez une règle pour la cible .DEFAULT. La recette d'une telle règle est utilisée pour tous les prérequis qui n'apparaissent comme cible d'aucune règle explicite et auxquels aucune règle implicite ne s'applique. Naturellement, la règle .DEFAULT n'existe pas tant que vous ne l'écrivez pas vous-même.

Si vous utilisez .DEFAULT sans recette ni prérequis :

.DEFAULT:

la recette précédemment stockée pour .DEFAULT est effacée. make se comporte alors comme si vous n'aviez jamais défini .DEFAULT du tout.

Si vous ne voulez pas qu'une certaine cible obtienne sa recette d'une règle de motif à correspondance universelle ou de .DEFAULT, mais que vous ne voulez pas non plus qu'aucune recette ne soit exécutée pour cette cible, vous pouvez lui donner une recette vide (voir Définir des recettes vides).

Vous pouvez aussi utiliser une règle de dernier recours pour remplacer une partie d'un autre makefile. Voir Remplacer une partie d'un autre Makefile.

10.7 Les règles de suffixe à l'ancienne

Les règles de suffixe (suffix rules) constituent la façon ancienne de définir des règles implicites pour make. Les règles de suffixe sont dépassées, parce que les règles de motif sont plus générales et plus claires. Elles sont prises en charge par GNU make pour la compatibilité avec les anciens makefiles. Il existe deux types de règles de suffixe : à double suffixe (double-suffix) et à suffixe unique (single-suffix).

Une règle à double suffixe est définie par une paire de suffixes : le suffixe de la cible et le suffixe de la source. Elle correspond à tout fichier dont le nom se termine par le suffixe de la cible. Le prérequis implicite correspondant se forme en remplaçant le suffixe de la cible par le suffixe de la source dans le nom de fichier. Une règle à double suffixe « .c.o » (dont le suffixe de la cible et le suffixe de la source sont respectivement « .o » et « .c ») est équivalente à la règle de motif « %.o : %.c ».

Une règle à suffixe unique est définie par un seul suffixe, qui est le suffixe de la source. Elle correspond à n'importe quel nom de fichier, et le nom du prérequis implicite correspondant se forme en ajoutant le suffixe de la source à la fin. Une règle à suffixe unique dont le suffixe de la source est « .c » est équivalente à la règle de motif « % : %.c ».

La définition d'une règle de suffixe est reconnue en comparant la cible de chaque règle à la liste prédéfinie des suffixes connus. Lorsque make trouve une règle dont la cible est un suffixe connu, il la considère comme une règle à suffixe unique. Lorsque make trouve une règle dont la cible est la concaténation de deux suffixes connus, il la considère comme une règle à double suffixe.

Par exemple, « .c » et « .o » figurent tous deux dans la liste par défaut des suffixes connus. Aussi, si vous définissez une règle dont la cible est « .c.o », make la considère comme une règle à double suffixe dont le suffixe de la source est « .c » et le suffixe de la cible « .o ». Voici la définition, à l'ancienne, d'une règle compilant les fichiers sources C :

.c.o:
        $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

Les règles de suffixe ne peuvent pas avoir de prérequis propres. Si elles en avaient, ceux-ci seraient traités non pas comme des règles de suffixe, mais comme des fichiers ordinaires portant des noms bizarres. Ainsi, la règle suivante :

.c.o: foo.h
        $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

indique comment produire le fichier .c.o à partir du fichier prérequis foo.h, et elle est tout à fait distincte de la règle de motif suivante :

%.o: %.c foo.h
        $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

Cette dernière indique comment produire un fichier « .o » à partir d'un fichier « .c » et fait en outre dépendre de foo.h tous les fichiers « .o » produits par cette règle de motif.

Une règle de suffixe sans recette est elle aussi dépourvue de sens. À la différence d'une règle de motif sans recette, qui supprime les règles précédentes (voir Annuler des règles implicites), elle ne supprime pas les règles précédentes. Elle se contente d'inscrire ce suffixe, ou cette paire de suffixes concaténés, comme cible dans la base de données.

Les suffixes connus ne sont en somme que les noms des prérequis de la cible spéciale .SUFFIXES. Vous pouvez ajouter vos propres suffixes en écrivant une règle qui ajoute des prérequis à .SUFFIXES, comme ceci :

.SUFFIXES: .hack .win

Ceci ajoute « .hack » et « .win » à la fin de la liste des suffixes.

Si vous voulez non pas ajouter aux suffixes connus par défaut, mais les retirer, écrivez une règle pour .SUFFIXES sans prérequis. Par une disposition spéciale, cela retire tous les prérequis existants de .SUFFIXES. Vous pouvez ensuite écrire une autre règle pour ajouter les suffixes que vous voulez. Par exemple :

.SUFFIXES:            # supprimer les suffixes par défaut
.SUFFIXES: .c .o .h   # définir sa propre liste de suffixes

Le drapeau « -r » ou « --no-builtin-rules » vide la liste des suffixes par défaut.

La variable SUFFIXES est définie comme la liste des suffixes par défaut avant que make ne lise aucun makefile. Vous pouvez modifier la liste des suffixes au moyen d'une règle pour la cible spéciale .SUFFIXES, mais cela ne change pas cette variable.

10.8 Algorithme de recherche des règles implicites

Voici la procédure que suit make pour rechercher une règle implicite applicable à une cible t. Cette procédure est suivie pour chaque règle à double deux-points sans recette, pour chaque cible des règles ordinaires sans recette, et pour chaque prérequis qui n'est la cible d'aucune règle. Elle est aussi suivie récursivement pour les prérequis issus d'une règle implicite, dans le cadre de la recherche d'une chaîne de règles.

Cet algorithme ne mentionne pas les règles de suffixe, parce que celles-ci sont converties en règles de motif équivalentes après que le makefile a été lu.

Pour une cible de membre d'archive de la forme « archive(member) », l'algorithme suivant est exécuté deux fois. La première fois en utilisant le nom de cible complet t ; si aucune règle n'a été trouvée lors de cette première passe, la seconde fois en utilisant « (member) » comme cible t.

  1. Découpez t en une partie répertoire (appelée d) et le reste (appelé n). Par exemple, si t est « src/foo.o », alors d est « src/ » et n est « foo.o ».
  2. Constituez la liste de toutes les règles de motif dont l'une des cibles correspond à t ou à n. Si le motif de cible contient une barre oblique, il est comparé à t ; sinon, il est comparé à n.
  3. Si cette liste contient au moins une règle qui n'est pas à correspondance universelle, ou si t est le prérequis d'une règle implicite, retirez de la liste toutes les règles non terminales à correspondance universelle.
  4. Retirez de la liste toutes les règles sans recette.
  5. Pour chaque règle de motif de la liste :
    1. Trouvez le radical s. C'est la partie non vide de t ou n à laquelle a correspondu le « % » du motif de cible.
    2. Calculez les noms des prérequis en substituant s au « % ». Si le motif de cible ne contient pas de barre oblique, ajoutez d en tête de chaque nom de prérequis.
    3. Vérifiez que tous les prérequis existent ou doivent exister. (On dit qu'un nom de fichier doit exister s'il est mentionné dans le makefile comme cible ou comme prérequis explicite de la cible T.)

      Si tous les prérequis existent ou doivent exister, ou s'il n'y a aucun prérequis, cette règle s'applique.

  6. Si aucune règle de motif n'a été trouvée jusqu'ici, faisons un effort supplémentaire. Pour chaque règle de motif de la liste :
    1. Si la règle est terminale, ignorez-la et passez à la règle suivante.
    2. Calculez les noms des prérequis comme précédemment.
    3. Vérifiez que tous les prérequis existent ou doivent exister.
    4. Pour chaque prérequis qui n'existe pas, suivez récursivement cet algorithme afin de déterminer si ce prérequis peut être produit par une règle implicite.
    5. Si tous les prérequis existent, doivent exister, ou peuvent être produits par une règle implicite, cette règle s'applique.
  7. Si aucune règle de motif n'a encore été trouvée, modifiez la définition de « doit exister » et reprenez les étapes 5 et 6. À savoir : un nom de fichier doit exister s'il est mentionné comme cible ou comme prérequis explicite de n'importe quelle cible. Cette vérification n'existe que pour la compatibilité ascendante avec d'anciennes versions de GNU Make. Nous vous déconseillons de vous y fier.
  8. Si aucune règle implicite ne s'applique, alors, s'il existe une règle pour .DEFAULT, c'est elle qui s'applique. Dans ce cas, t reçoit la même recette que celle de .DEFAULT. Sinon, t n'a pas de recette.

Une fois qu'une règle applicable a été trouvée, pour chaque motif de cible de cette règle autre que celui qui a correspondu à t ou n, le « % » du motif est remplacé par s, et le nom de fichier ainsi obtenu est conservé jusqu'à ce que la recette qui refait le fichier cible t soit exécutée. Après l'exécution de la recette, chacun de ces noms de fichiers conservés est inscrit dans la base de données et marqué comme mis à jour, avec le même statut de mise à jour que le fichier t.

Lorsque la recette d'une règle de motif est exécutée pour t, les variables automatiques sont définies en fonction de sa cible et de ses prérequis. Voir Variables automatiques.


Précédent | Suivant | Sommaire | Version originale anglaise (gnu.org)