Réponses:
Par défaut, les cibles Makefile sont des "cibles de fichiers" - elles sont utilisées pour créer des fichiers à partir d'autres fichiers. Make suppose que sa cible est un fichier, ce qui rend l'écriture de Makefiles relativement facile:
foo: bar
create_one_from_the_other foo bar
Cependant, vous souhaitez parfois que votre Makefile exécute des commandes qui ne représentent pas des fichiers physiques dans le système de fichiers. De bons exemples en sont les cibles communes «propre» et «tout». Ce n'est probablement pas le cas, mais vous pouvez potentiellement avoir un fichier nommé clean
dans votre répertoire principal. Dans un tel cas, Make sera confus parce que par défaut la clean
cible serait associée à ce fichier et Make ne l'exécutera que lorsque le fichier ne semble pas à jour en ce qui concerne ses dépendances.
Ces cibles spéciales sont appelées fausses et vous pouvez dire explicitement à Make qu'elles ne sont pas associées à des fichiers, par exemple:
.PHONY: clean
clean:
rm -rf *.o
Exécute maintenant make clean
comme prévu même si vous avez un fichier nommé clean
.
En termes de Make, une fausse cible est simplement une cible qui est toujours obsolète, donc chaque fois que vous le demandez make <phony_target>
, elle s'exécutera, indépendamment de l'état du système de fichiers. Certaines communes make
cibles qui sont souvent faux sont: all
, install
, clean
, distclean
, TAGS
, info
, check
.
Supposons que vous ayez une install
cible, ce qui est très courant dans les makefiles. Si vous ne pas utiliser .PHONY
, et un fichier nommé install
existe dans le même répertoire que le Makefile, puis make install
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
". Puisque le fichier est déjà là et que ses dépendances n'ont pas changé, rien ne sera fait.
Cependant, si vous créez la install
PHONIE cible, il indiquera à l'outil de création que la cible est fictive, et que la marque ne doit pas s'attendre à ce qu'elle crée le fichier réel. Par conséquent, il ne vérifiera pas si le install
fichier existe, ce qui signifie: a) son comportement ne sera pas modifié si le fichier existe et b) extra stat()
ne sera pas appelé.
Généralement, toutes les cibles de votre Makefile qui ne produisent pas de fichier de sortie portant le même nom que le nom cible doivent être PHONY. Cela comprend généralement all
, install
, clean
, distclean
et ainsi de suite.
.sh
or .bash
pour les "programmes" qui s'exécutent comme s'ils avaient une fonction principale et de réserver l'ajout d'une extension pour les bibliothèques que vous incluez ( source mylib.sh
). En fait, je suis arrivé à cette question SO parce que j'avais un script dans le même répertoire que mon Makefile appeléinstall
.PHONY
tout le temps ...
.PHONY
version.
REMARQUE : l'outil make lit le makefile et vérifie les horodatages de modification des fichiers à la fois du côté du symbole ':' dans une règle.
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, qui a été créé après le fichier «hello.c». Ainsi, l'horodatage de modification (ou de création) de «bonjour» sera plus récent que celui de «bonjour.c». Ainsi, lorsque nous invoquerons «faire bonjour» à partir de la ligne de commande, il s'affichera comme suit:
make: `hello' is up to date.
Accédez maintenant au fichier 'hello.c' et placez-y des espaces blancs, ce qui n'affecte pas la syntaxe ou la logique du code, puis enregistrez et quittez. Maintenant, l'horodatage de modification de hello.c est plus récent que celui de 'hello'. Maintenant, si vous appelez «make hello», il exécutera les commandes comme suit:
cc hello.c -o hello
Et le fichier 'hello' (fichier texte) sera remplacé par un nouveau fichier binaire 'hello' (résultat de la commande de compilation ci-dessus).
Si nous utilisons .PHONY dans le makefile comme suit:
.PHONY:hello
hello:hello.c
cc hello.c -o hello
puis appelez «make hello», il ignorera tout fichier présent dans le test «pwd» et exécutera la commande à chaque fois.
Supposons maintenant que cette cible 'hello' n'ait aucune dépendance déclarée:
hello:
cc hello.c -o hello
et le fichier 'hello' est déjà présent dans le test 'pwd', alors 'make hello' apparaîtra toujours comme:
make: `hello' is up to date.
make
un sens à l'ensemble, c'est une question de fichiers! Merci pour cette réponse.
.PHONY: install
La meilleure explication est le manuel GNU make lui-même: 4.6 Section Phony Targets .
.PHONY
est l'un des noms de cible intégrés spéciaux de make . Il existe d'autres cibles qui pourraient vous intéresser, il vaut donc la peine de parcourir ces références.
Lorsqu'il est temps d'envisager une cible .PHONY, make exécutera sa recette sans condition, indépendamment de l'existence d'un fichier portant ce nom ou de l'heure de sa 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" - quand une cible physique dépend d'une cible bidon qui dépend d'une autre cible physique:
TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2
Vous vous attendez simplement à ce que si vous mettez à jour TARGET2, TARGET1 doit être considéré comme périmé par rapport à TARGET1, donc TARGET1 doit être reconstruit. Et cela fonctionne vraiment de cette façon .
La partie délicate est lorsque TARGET2 n'est pas périmé par rapport à TARGET1 - auquel cas vous devez vous attendre à ce que TARGET1 ne soit pas reconstruit.
Cela ne fonctionne étonnamment pas parce que: la cible bidon a quand même été exécutée (comme le font normalement les cibles bidon) , ce qui signifie que la cible bidon a été considérée comme mise à jour . Et à cause de cela, TARGET1 est considéré comme périmé par rapport à la fausse cible .
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:
Vous pouvez voir que fileall dépend indirectement de file1 via une cible bidon - mais il est toujours reconstruit en raison de cette dépendance. Si vous modifiez la dépendance fileall
de filefwd
à file
, maintenant fileall
ne sera pas reconstruit à chaque fois, mais uniquement lorsque l'une des cibles dépendantes est périmée en tant que fichier.
La cible spéciale .PHONY:
permet de déclarer des cibles bidon, ce qui make
ne les vérifiera pas comme des noms de fichiers réels: cela fonctionnera tout le temps même si de tels fichiers existent toujours.
Vous pouvez en mettre plusieurs .PHONY:
dans Makefile
:
.PHONY: all
all : prog1 prog2
...
.PHONY: clean distclean
clean :
...
distclean :
...
Il existe une autre façon de déclarer des cibles bidon: il suffit de mettre '::'
all :: prog1 prog2
...
clean ::
...
distclean ::
...
Le '::' a une signification particulière: les cibles sont fausses et peuvent apparaître plusieurs fois:
clean ::
rm file1
...
clean ::
rm file2
Les blocs de commandes seront appelés les uns après les autres.
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
tireraient clean
, andsomethingelse
et catcher superclean
; mais avec PHONY, make superclean
ne tirera pas le catcher superclean
.
Nous n'avons pas à nous soucier de dire que la clean
cible est PHONY, car elle n'est pas complètement bidon. Bien qu'il ne produise jamais le fichier propre, il a des commandes à tirer, donc make pensera que c'est une cible finale.
Cependant, la superclean
cible est vraiment bidon, alors make essaiera de l'empiler avec tout ce qui fournit des deps pour la superclean
cible - cela inclut d'autres superclean
cibles et la %
cible.
Notez que nous ne disons rien du tout sur andsomethingelse
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