Risposte:
Per impostazione predefinita, le destinazioni Makefile sono "destinazioni file": vengono utilizzate per creare file da altri file. Make presuppone che il suo target sia un file e questo rende la scrittura di Makefile relativamente semplice:
foo: bar
create_one_from_the_other foo bar
Tuttavia, a volte si desidera che Makefile esegua comandi che non rappresentano file fisici nel file system. Buoni esempi per questo sono gli obiettivi comuni "clean" e "all". È probabile che non sia così, ma potresti avere potenzialmente un file chiamato clean
nella tua directory principale. In tal caso, Make sarà confuso perché per impostazione predefinita la clean
destinazione sarebbe associata a questo file e Make lo eseguirà solo quando il file non sembra essere aggiornato in relazione alle sue dipendenze.
Questi target speciali sono chiamati fasulli e puoi dire esplicitamente a Make che non sono associati ai file, ad esempio:
.PHONY: clean
clean:
rm -rf *.o
Ora make clean
funzionerà come previsto anche se hai un file chiamato clean
.
In termini di Make, un target fasullo è semplicemente un target che è sempre obsoleto, quindi ogni volta che lo chiedi make <phony_target>
, verrà eseguito, indipendentemente dallo stato del file system. Alcuni comuni make
obiettivi che sono spesso falsi sono: all
, install
, clean
, distclean
, TAGS
, info
, check
.
Supponiamo che tu abbia un install
target, che è molto comune nei makefile. Se non si utilizza .PHONY
ed install
esiste un file denominato nella stessa directory del Makefile, allora make install
non farà nulla . Questo perché Make interpreta la regola nel senso che "esegue tale ricetta per creare il file denominato install
". Poiché il file è già lì e le sue dipendenze non sono cambiate, non verrà fatto nulla.
Tuttavia, se si crea il install
target PHONY, questo indicherà allo strumento make che il target è fittizio e che make non dovrebbe aspettarsi che crei il file effettivo. Quindi non verificherà se il install
file esiste, ovvero: a) il suo comportamento non verrà modificato se il file esiste e b) extra stat()
non verrà chiamato.
Generalmente tutte le destinazioni nel tuo Makefile che non producono un file di output con lo stesso nome del nome di destinazione dovrebbero essere PHONY. Questo include in genere all
, install
, clean
, distclean
, e così via.
.sh
o .bash
"i programmi" che funzionano come se avessero una funzione principale e riservano l'aggiunta di un'estensione per le librerie che includi ( source mylib.sh
). In effetti, sono arrivato a questa domanda SO perché avevo uno script nella stessa directory del mio Makefile chiamatoinstall
.PHONY
sempre ...
.PHONY
versione.
NOTA : lo strumento make legge il makefile e controlla i timestamp di modifica dei file su entrambi i lati del simbolo ':' in una regola.
In una directory 'test' sono presenti i seguenti file:
prerit@vvdn105:~/test$ ls
hello hello.c makefile
Nel makefile una regola è definita come segue:
hello:hello.c
cc hello.c -o hello
Ora supponiamo che il file 'ciao' sia un file di testo contenente alcuni dati, che è stato creato dopo il file 'ciao.c'. Quindi il timestamp di modifica (o creazione) di 'hello' sarà più recente di quello di 'hello.c'. Quindi quando invocheremo 'make hello' dalla riga di comando, verrà stampato come:
make: `hello' is up to date.
Ora accedi al file 'hello.c' e inserisci degli spazi bianchi, che non influiscono sulla sintassi o sulla logica del codice, quindi salva ed esci. Ora il timestamp di modifica di hello.c è più recente di quello di 'hello'. Ora se invochi 'make hello', eseguirà i comandi come:
cc hello.c -o hello
E il file 'ciao' (file di testo) verrà sovrascritto con un nuovo file binario 'ciao' (risultato del comando di compilazione sopra).
Se usiamo .PHONY nel makefile come segue:
.PHONY:hello
hello:hello.c
cc hello.c -o hello
e quindi invoca 'make hello', ignorerà qualsiasi file presente nel pwd 'test' ed eseguirà il comando ogni volta.
Supponiamo ora che quel bersaglio "ciao" non abbia dipendenze dichiarate:
hello:
cc hello.c -o hello
e il file 'hello' è già presente nel pwd 'test', quindi 'make hello' mostrerà sempre come:
make: `hello' is up to date.
make
che abbia un senso nel suo insieme, dipende solo dai file! Grazie per questa risposta
.PHONY: install
La migliore spiegazione è lo stesso manuale di GNU make: 4.6 Sezione Targeting per falso .
.PHONY
è uno dei nomi target incorporati speciali di make . Ci sono altri obiettivi che potrebbero interessarti, quindi vale la pena scorrere questi riferimenti.
Quando è il momento di prendere in considerazione un obiettivo .PHONY, make eseguirà la sua ricetta incondizionatamente, indipendentemente dal fatto che esista un file con quel nome o quale sia il suo ultimo tempo di modifica.
Potresti anche essere interessato a target standard di make come all
e clean
.
C'è anche un'importante sorpresa di ".PHONY" - quando un bersaglio fisico dipende da un bersaglio falso che dipende da un altro bersaglio fisico:
TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2
Ti aspetteresti semplicemente che se hai aggiornato TARGET2, TARGET1 dovrebbe essere considerato obsoleto rispetto a TARGET1, quindi TARGET1 dovrebbe essere ricostruito. E funziona davvero così .
La parte difficile è quando TARGET2 non è stantio rispetto a TARGET1, nel qual caso dovresti aspettarti che TARGET1 non debba essere ricostruito.
Ciò sorprendentemente non funziona perché: il target falso è stato eseguito comunque (come normalmente fanno i target falsi) , il che significa che il target falso è stato considerato aggiornato . E a causa di ciò TARGET1 è considerato stantio contro il bersaglio falso .
Prendere in considerazione:
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
Puoi giocare con questo:
Puoi vedere che fileall dipende indirettamente da file1 attraverso un obiettivo falso, ma viene sempre ricostruito a causa di questa dipendenza. Se modifichi la dipendenza fileall
da da filefwd
a file
, ora fileall
non viene ricostruita ogni volta, ma solo quando uno dei target dipendenti è stantio contro di esso come file.
Il target speciale .PHONY:
consente di dichiarare target falsi, in modo che make
non li controlli come nomi di file effettivi: funzionerà continuamente anche se tali file esistono ancora.
Puoi metterne diversi .PHONY:
nel tuo Makefile
:
.PHONY: all
all : prog1 prog2
...
.PHONY: clean distclean
clean :
...
distclean :
...
Esiste un altro modo per dichiarare bersagli falsi: basta inserire '::'
all :: prog1 prog2
...
clean ::
...
distclean ::
...
Il '::' ha un significato speciale: gli obiettivi sono falsi e possono apparire più volte:
clean ::
rm file1
...
clean ::
rm file2
I blocchi di comandi verranno chiamati uno dopo l'altro.
Li uso spesso per dire al bersaglio predefinito di non sparare.
superclean: clean andsomethingelse
blah: superclean
clean:
@echo clean
%:
@echo catcher $@
.PHONY: superclean
Senza falsi, make superclean
avrebbe sparato clean
, andsomethingelse
e catcher superclean
; ma con PHONY, make superclean
non sparerà catcher superclean
.
Non dobbiamo preoccuparci di dire che l' clean
obiettivo è PHONY, perché non è completamente falso. Sebbene non produca mai il file pulito, ha i comandi da sparare, quindi make penserà che sia un obiettivo finale.
Tuttavia, il superclean
target è davvero falso, quindi make cercherà di impilarlo con qualsiasi altra cosa che fornisca deps al superclean
target - questo include altri superclean
target e il %
target.
Nota che non diciamo assolutamente nulla andsomethingelse
o blah
, quindi vanno chiaramente al ricevitore.
L'output è simile al seguente:
$ make clean
clean
$ make superclean
clean
catcher andsomethingelse
$ make blah
clean
catcher andsomethingelse
catcher blah