Odpowiedzi:
Domyślnie cele Makefile są „celami plików” - służą do budowania plików z innych plików. Make przyjmuje, że jego celem jest plik, a to sprawia, że pisanie Makefiles jest stosunkowo łatwe:
foo: bar
create_one_from_the_other foo bar
Czasami jednak chcesz, aby Twój Makefile uruchamiał polecenia, które nie reprezentują fizycznych plików w systemie plików. Dobrym przykładem tego są wspólne cele „czyste” i „wszystkie”. Możliwe, że tak nie jest, ale potencjalnie plik może mieć nazwę clean
w katalogu głównym. W takim przypadku Make zostanie zdezorientowany, ponieważ domyślnie clean
cel będzie powiązany z tym plikiem, a Make uruchomi go tylko wtedy, gdy plik nie wydaje się być aktualny w odniesieniu do jego zależności.
Te specjalne cele nazywane są fałszywymi i możesz wyraźnie powiedzieć Make, że nie są powiązane z plikami, np .:
.PHONY: clean
clean:
rm -rf *.o
Teraz make clean
będzie działać zgodnie z oczekiwaniami, nawet jeśli masz plik o nazwie clean
.
Pod względem marki fałszywy cel to po prostu cel, który jest zawsze nieaktualny, więc za każdym razem, gdy o to poprosisz make <phony_target>
, będzie działał niezależnie od stanu systemu plików. Pewne wspólne make
cele, które są często fałszywe są: all
, install
, clean
, distclean
, TAGS
, info
, check
.
Załóżmy, że masz install
cel, który jest bardzo powszechny w plikach makefile. Jeśli nie używasz .PHONY
, a plik o nazwie install
istnieje w tym samym katalogu co plik Makefile, nic niemake install
zrobi . Wynika to z faktu, że Make interpretuje regułę w ten sposób, że oznacza „wykonaj taką i inną receptę, aby utworzyć plik o nazwie ”. Ponieważ plik już tam jest, a jego zależności się nie zmieniły, nic nie zostanie zrobione.install
Jeśli jednak install
ustawisz docelowy obiekt PHONY, powie on narzędziu make, że cel jest fikcyjny, i marka nie powinna oczekiwać, że utworzy rzeczywisty plik. Dlatego nie sprawdzi, czy install
plik istnieje, co oznacza: a) jego zachowanie nie zostanie zmienione, jeśli plik istnieje, oraz b) dodatkowe stat()
nie zostaną wywołane.
Zasadniczo wszystkie cele w twoim Makefile, które nie tworzą pliku wyjściowego o takiej samej nazwie jak nazwa celu, powinny mieć wartość PHONY. To zazwyczaj obejmuje all
, install
, clean
, distclean
, i tak dalej.
.sh
lub .bash
” dla programów, które działają tak, jakby miały główną funkcję, i rezerwowanie dodawania rozszerzenia dla bibliotek, które dołączasz ( source mylib.sh
). W rzeczywistości dotarłem do tego pytania SO, ponieważ miałem skrypt w tym samym katalogu, co mój Makefile o nazwieinstall
.PHONY
cały czas ...
.PHONY
wersją.
UWAGA : Narzędzie make odczytuje plik makefile i sprawdza znaczniki czasu modyfikacji plików po obu stronach symbolu „:” w regule.
W katalogu „test” obecne są następujące pliki:
prerit@vvdn105:~/test$ ls
hello hello.c makefile
W makefile reguła jest zdefiniowana następująco:
hello:hello.c
cc hello.c -o hello
Załóżmy teraz, że plik „hello” to plik tekstowy zawierający pewne dane, który został utworzony po pliku „hello.c”. Tak więc znacznik czasu modyfikacji (lub tworzenia) „hello” będzie nowszy niż znacznik „hello.c”. Kiedy więc wywołamy „make hello” z wiersza poleceń, zostanie wydrukowany jako:
make: `hello' is up to date.
Teraz uzyskaj dostęp do pliku „hello.c” i umieść w nim trochę białych znaków, co nie wpływa na składnię ani logikę kodu, a następnie zapisz i wyjdź. Teraz znacznik czasu modyfikacji hello.c jest nowszy niż znacznik „hello”. Teraz, jeśli wywołasz „make hello”, wykona polecenia w następujący sposób:
cc hello.c -o hello
Plik „hello” (plik tekstowy) zostanie zastąpiony nowym plikiem binarnym „hello” (wynik powyższego polecenia kompilacji).
Jeśli użyjemy .PHONY w pliku makefile w następujący sposób:
.PHONY:hello
hello:hello.c
cc hello.c -o hello
a następnie wywołać „make hello”, zignoruje każdy plik obecny w „teście pwd” i wykona polecenie za każdym razem.
Załóżmy teraz, że cel „cześć” nie ma zadeklarowanych zależności:
hello:
cc hello.c -o hello
a plik „hello” jest już obecny w „teście” pwd, wtedy „make hello” będzie zawsze wyświetlane jako:
make: `hello' is up to date.
make
jako całość mają sens, to wszystko dotyczy plików! Dziękuję za tę odpowiedź.
.PHONY: install
Najlepszym wyjaśnieniem jest sam GNU make manual: sekcja 4.6 Fikcyjne cele .
.PHONY
jest jedną z wbudowanych specjalnych nazw marek . Istnieją inne cele, które mogą Cię zainteresować, więc warto przejrzeć te odniesienia.
Kiedy przyjdzie czas na rozważenie celu .PHONY, make uruchomi swój przepis bezwarunkowo, niezależnie od tego, czy istnieje plik o tej nazwie lub jaki jest czas ostatniej modyfikacji.
Możesz być także zainteresowany standardowymi celami marki, takimi jak all
i clean
.
Jest też jedna ważna podstępna metoda „.PHONY” - kiedy cel fizyczny zależy od fałszywego celu, który zależy od innego celu fizycznego:
TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2
Po prostu można oczekiwać, że jeśli zaktualizujesz TARGET2, to TARGET1 należy uznać za nieaktualny w stosunku do TARGET1, więc TARGET1 powinien zostać odbudowany. I to naprawdę działa w ten sposób .
Trudna część polega na tym, że TARGET2 nie jest przestarzały w stosunku do TARGET1 - w takim przypadku należy spodziewać się, że TARGET1 nie powinien zostać odbudowany.
To zaskakująco nie działa, ponieważ: fałszywy cel i tak został uruchomiony (jak zwykle fałszywe cele) , co oznacza, że fałszywy cel został uznany za zaktualizowany . Z tego powodu TARGET1 jest uważany za przestarzały w stosunku do fałszywego celu .
Rozważać:
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
Możesz się tym pobawić:
Możesz zobaczyć, że fileall zależy od file1 pośrednio poprzez fałszywy cel - ale zawsze jest odbudowywany z powodu tej zależności. Jeśli zmienisz zależność fileall
z filefwd
na file
, teraz fileall
nie będzie ona przebudowywana za każdym razem, ale tylko wtedy, gdy któryś z zależnych celów jest nieaktualny w stosunku do niego jako plik.
Specjalny cel .PHONY:
pozwala zadeklarować fałszywe cele, aby make
nie sprawdzały ich jako rzeczywistych nazw plików: będzie działał przez cały czas, nawet jeśli takie pliki nadal istnieją.
Możesz umieścić kilka .PHONY:
w swoim Makefile
:
.PHONY: all
all : prog1 prog2
...
.PHONY: clean distclean
clean :
...
distclean :
...
Istnieje inny sposób deklarowania fałszywych celów: wystarczy wpisać „::”
all :: prog1 prog2
...
clean ::
...
distclean ::
...
„::” ma specjalne znaczenie: cele są fałszywe, a ponadto mogą pojawiać się kilka razy:
clean ::
rm file1
...
clean ::
rm file2
Bloki poleceń będą wywoływane jeden po drugim.
Często używam ich, aby powiedzieć domyślnemu celowi, aby nie strzelał.
superclean: clean andsomethingelse
blah: superclean
clean:
@echo clean
%:
@echo catcher $@
.PHONY: superclean
Bez fałszywej, make superclean
by ogień clean
, andsomethingelse
i catcher superclean
; ale dzięki PHONY make superclean
nie zwolni catcher superclean
.
Nie musimy się martwić, że clean
celem będzie PHONY, ponieważ nie jest on całkowicie fałszywy. Chociaż nigdy nie tworzy czystego pliku, ma polecenia do uruchomienia, więc make pomyśli, że jest to ostateczny cel.
Jednak superclean
cel jest naprawdę fałszywy, więc make spróbuje go ułożyć w stos z czymkolwiek innym, co zapewnia dep dla superclean
celu - w tym inne superclean
cele i %
cel.
Zauważ, że nie mówimy nic o andsomethingelse
lub blah
, więc najwyraźniej idą do łapacza.
Dane wyjściowe wyglądają mniej więcej tak:
$ make clean
clean
$ make superclean
clean
catcher andsomethingelse
$ make blah
clean
catcher andsomethingelse
catcher blah