Quel est le but de .PHONY dans un makefile?

Que signifie .PHONY dans un Makefile? Je suis passé par là , mais c’est trop compliqué.

Quelqu’un peut-il me l’expliquer en termes simples?

Par défaut, les cibles Makefile sont des “cibles de fichier” – elles sont utilisées pour créer des fichiers à partir d’autres fichiers. Make suppose que sa cible est un fichier, ce qui facilite l’écriture des Makefiles:

 foo: bar create_one_from_the_other foo bar 

Cependant, vous voulez parfois que votre Makefile exécute des commandes qui ne représentent pas des fichiers physiques dans le système de fichiers. Les bons exemples pour cela sont les objectives communs “propres” et “tous”. Les chances sont que ce n’est pas le cas, mais vous pouvez éventuellement avoir un fichier nommé clean dans votre répertoire principal. Dans un tel cas, Make sera confus car par défaut, la cible clean sera associée à ce fichier et Make l’exécutera uniquement si le fichier ne semble pas être à jour en ce qui concerne ses dépendances.

Ces cibles spéciales sont appelées phony et vous pouvez dire explicitement à Make qu’elles ne sont pas associées à des fichiers, par exemple:

 .PHONY: clean clean: rm -rf *.o 

Maintenant, make clean s’exécutera comme prévu même si vous avez un fichier nommé clean .

En termes de Make, une cible bidon est simplement une cible qui est toujours obsolète, donc à chaque fois que vous posez la question make , elle s’exécutera, indépendamment de l’état du système de fichiers. Les cibles les plus courantes qui sont souvent bidon sont: all , install , clean , clean , TAGS , info , check .

Supposons que vous ayez une cible d’ install , ce qui est très courant dans les makefiles. Si vous n’utilisez pas .PHONY et qu’un fichier nommé install existe dans le même répertoire que le Makefile, make install ne fera rien . En effet, Make interprète la règle comme signifiant “exécuter telle ou telle recette pour créer le fichier nommé install “. Comme le fichier est déjà là et que ses dépendances n’ont pas changé, rien ne sera fait.

Cependant, si vous définissez la cible d’ install PHONY, cela indiquera à l’outil de création que la cible est fictive, ce qui ne devrait pas entraîner la création du fichier réel. Par conséquent, il ne vérifie pas si le fichier d’ install existe, ce qui signifie: a) son comportement ne sera pas modifié si le fichier existe et b) extra stat() ne sera pas appelé.

En général, toutes les cibles de votre Makefile qui ne produisent pas un fichier de sortie portant le même nom que le nom cible doivent être PHONY. Cela comprend généralement all , install , clean , distclean , etc.

REMARQUE : L’outil make lit le fichier makefile et vérifie les horodatages de modification des fichiers situés du côté du symbole ‘:’ dans une règle.

Exemple

Dans un répertoire ‘test’, les fichiers suivants sont présents:

 prerit@vvdn105:~/test$ ls hello hello.c makefile 

Dans makefile, une règle est définie comme suit:

 hello:hello.c cc hello.c -o hello 

Supposons maintenant que le fichier ‘hello’ est un fichier texte contenant des données, créé après le fichier ‘hello.c’. Ainsi, l’horodatage de modification (ou de création) de ‘hello’ sera plus récent que celui de ‘hello.c’. Ainsi, lorsque nous invoquerons ‘make hello’ à partir de la ligne de commande, il sera imprimé comme suit:

 make: `hello' is up to date. 

Accédez maintenant au fichier ‘hello.c’ et placez-y des espaces blancs, qui n’affectent pas la syntaxe ou la logique du code, puis sauvegardez et fermez. Maintenant, l’horodatage de modification de hello.c est plus récent que celui du ‘hello’. Maintenant, si vous appelez ‘make hello’, les commandes seront exécutées comme suit:

 cc hello.c -o hello 

Et le fichier ‘hello’ (fichier texte) sera remplacé par un nouveau fichier binary ‘hello’ (résultat de la commande de compilation ci-dessus).

Si nous utilisons .PHONY dans makefile comme suit:

 .PHONY:hello hello:hello.c cc hello.c -o hello 

et ensuite invoquer ‘make hello’, il ignorera si un fichier présent dans le fichier pwd s’appelle ‘hello’ et exécute la commande à chaque fois.

Supposons maintenant que si aucune dépendance de la cible n’existe dans le fichier makefile:

 hello: cc hello.c -o hello 

et le fichier ‘hello’ est déjà présent dans pwd ‘test’, alors ‘make hello’ sera toujours affiché comme:

 make: `hello' is up to date. 
 .PHONY: install 
  • signifie que le mot “install” ne représente pas un nom de fichier dans ce Makefile;
  • signifie que le Makefile n’a rien à voir avec un fichier appelé “install” dans le même répertoire.

C’est une cible de construction qui n’est pas un nom de fichier.

La meilleure explication est le manuel de make GNU lui-même: 4.6 Section Phony Targets .

.PHONY est l’un des noms de cible .PHONY de make. Il y a d’autres cibles qui peuvent vous intéresser, alors il vaut mieux parcourir ces références.

Lorsqu’il est temps d’envisager une cible .PHONY, make lance sa recette sans condition, qu’il existe ou non un fichier portant ce nom ou l’heure de dernière modification.

Vous pouvez également être intéressé par les cibles standard de make telles que all et clean .

Il y a aussi un traitement délicat important de “.PHONY” – lorsqu’une cible physique dépend d’une cible bidon qui dépend d’une autre cible physique:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

Vous devez simplement vous attendre à ce que, si vous mettez à jour TARGET2, alors TARGET1 soit considéré comme obsolète par rapport à TARGET1, de sorte que TARGET1 doit être reconstruit. Et ça marche vraiment comme ça .

La partie la plus délicate est que lorsque TARGET2 n’est pas obsolète contre TARGET1, vous devez vous attendre à ce que TARGET1 ne soit pas reconstruit.

Cela ne marche pas de manière surprenante car: la cible bidon a été exécutée de toute façon (comme le font normalement les cibles bidons) , ce qui signifie que la cible bidon a été considérée comme mise à jour . Et à cause de cela, TARGET1 est considéré comme obsolète par rapport à la cible bidon .

Considérer:

 all: fileall fileall: file2 filefwd echo file2 file1 >fileall file2: file2.src echo file2.src >file2 file1: file1.src echo file1.src >file1 echo file1.src >>file1 .PHONY: filefwd .PHONY: filefwd2 filefwd: filefwd2 filefwd2: file1 @echo "Produced target file1" prepare: echo "Some text 1" >> file1.src echo "Some text 2" >> file2.src 

Vous pouvez jouer avec ceci:

  • tout d’abord faire “préparer” pour préparer les “fichiers source”
  • jouer avec cela en touchant des fichiers particuliers pour les voir mis à jour

Vous pouvez voir que fileall dépend indirectement de fichier1 via une cible bidon – mais il est toujours reconstruit en raison de cette dépendance. Si vous modifiez la dépendance dans fileall de filefwd en file , maintenant, fileall ne sera pas reconstruit à chaque fois, mais uniquement lorsque l’une des cibles dépendantes est obsolète en tant que fichier.

Je les utilise souvent pour dire à la cible par défaut de ne pas tirer.

 superclean: clean andsomethingelse blah: superclean clean: @echo clean %: @echo catcher $@ .PHONY: superclean 

Sans PHONY, make superclean tirerait clean , et catcher superclean ; mais avec PHONY, make superclean ne déclenche pas le catcher superclean .

Nous n’avons pas à nous soucier de dire que la cible clean est PHONY, car ce n’est pas complètement faux. Bien qu’il ne produise jamais le fichier propre, il a des commandes à lancer, donc pense qu’il s’agira d’une cible finale.

Cependant, la cible superclean est vraiment fausse, donc make essaiera de la superclean avec tout ce qui fournit des deps pour la cible superclean – ceci inclut d’autres cibles superclean et la cible % .

Notez que nous ne disons rien à propos de quelque chose et de quelque chose ou blah , donc ils vont clairement au receveur.

La sortie ressemble à ceci:

 $ make clean clean $ make superclean clean catcher andsomethingelse $ make blah clean catcher andsomethingelse catcher blah