Was ist der Zweck von .PHONY in einem Makefile?

1738

Was .PHONYbedeutet in einem Makefile? Ich habe durchgemacht dies , aber es ist zu kompliziert.

Kann es mir jemand in einfachen Worten erklären?

Laser
quelle

Antworten:

1947

Standardmäßig sind Makefile-Ziele "Dateiziele" - sie werden zum Erstellen von Dateien aus anderen Dateien verwendet. Make geht davon aus, dass das Ziel eine Datei ist, und dies macht das Schreiben von Makefiles relativ einfach:

foo: bar
  create_one_from_the_other foo bar

Manchmal möchten Sie jedoch, dass Ihr Makefile Befehle ausführt, die keine physischen Dateien im Dateisystem darstellen. Gute Beispiele dafür sind die gemeinsamen Ziele "sauber" und "alle". Möglicherweise ist dies nicht der Fall, aber möglicherweise befindet sich eine Datei mit dem Namen cleanin Ihrem Hauptverzeichnis. In einem solchen Fall wird Make verwirrt, da das cleanZiel standardmäßig dieser Datei zugeordnet ist und Make es nur ausführt, wenn die Datei hinsichtlich ihrer Abhängigkeiten nicht auf dem neuesten Stand zu sein scheint.

Diese speziellen Ziele werden als falsch bezeichnet und Sie können explizit festlegen, dass Make nicht mit Dateien verknüpft ist, z.

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

Jetzt make cleanwird es wie erwartet ausgeführt, auch wenn Sie eine Datei mit dem Namen haben clean.

In Bezug auf Make ist ein falsches Ziel einfach ein Ziel, das immer veraltet ist. Wenn Sie also danach fragen make <phony_target>, wird es unabhängig vom Status des Dateisystems ausgeführt. Einige gemeinsame makeZiele , die oft unecht sind: all, install, clean, distclean, TAGS, info, check.

Eli Bendersky
quelle
49
@eSKay: 'Warum heißt es' falsch '?' - weil es kein echtes Ziel ist. Das heißt, der Zielname ist keine Datei, die von den Befehlen dieses Ziels erzeugt wird.
Bernard
96
@Lazer: Ich weiß nicht, ob Sie Englisch als Muttersprache haben. Ich bin nicht. Das Wort "falsch" bedeutet nicht, wie es sich anhört. en.wiktionary.org/wiki/phony sagt: Betrügerisch; Fälschung; ein irreführendes Aussehen haben.
Bahbar
57
Diese Antwort ist nicht genau vollständig - obwohl sie möglicherweise im verknüpften Tutorial behandelt wird. .PHONY erzwingt die Erstellung eines Labels / einer Datei in einem Makefile, wenn es Teil der topologischen Art Ihres Ziels ist. Das heißt, wenn Sie ein falsch gesetztes Label 'cleanup:' haben und Ihr Installationslabel mit cleanup als Voraussetzung definiert ist, dh 'install: cleanup', wird die Bereinigung immer ausgeführt, wenn das Makefile versucht, sie zu erstellen 'Installieren'. Dies ist nützlich für Schritte, die Sie immer ausführen möchten, unabhängig davon, ob sie erfolgreich sind. Zeitstempel werden ignoriert und nur erzwungen.
Synthesizerpatel
9
Beachten Sie, dass Sie .PHONY nicht verwenden müssen, solange Sie keine Datei mit demselben Namen wie die Aufgabe haben. Die Aufgabe wird trotzdem immer ausgeführt und das Makefile ist besser lesbar.
Bernard
15
"Ein falsches Ziel ist einfach ein Ziel, das immer veraltet ist" - eine großartige Erklärung!
Danijel
730

Nehmen wir an, Sie haben ein installZiel, was in Makefiles sehr häufig vorkommt. Wenn Sie nicht verwenden .PHONYund eine Datei mit dem Namen installim selben Verzeichnis wie das Makefile vorhanden ist, make installwird nichts unternommen . Dies liegt daran, dass Make die Regel so interpretiert, dass sie "das eine oder andere Rezept ausführen, um die Datei mit dem Namen zu erstellen install" bedeutet. Da die Datei bereits vorhanden ist und sich ihre Abhängigkeiten nicht geändert haben, wird nichts unternommen.

Wenn Sie jedoch das installZiel PHONY erstellen, teilt es dem make-Tool mit, dass das Ziel fiktiv ist und dass make nicht erwarten sollte, dass es die eigentliche Datei erstellt. Daher wird nicht geprüft, ob die installDatei vorhanden ist, was bedeutet: a) ihr Verhalten wird nicht geändert, wenn die Datei vorhanden ist, und b) extra stat()wird nicht aufgerufen.

Im Allgemeinen sollten alle Ziele in Ihrem Makefile, die keine Ausgabedatei mit demselben Namen wie der Zielname erzeugen, PHONY sein. Dies umfasst in der Regel all, install, clean, distclean, und so weiter.

George Y.
quelle
6
@PineappleUndertheSea Die akzeptierte Antwort wurde von ihrem anfänglichen Grad an Wertlosigkeit erheblich verbessert und ist jetzt genauso gut wie diese. Ich musste den Revisionsverlauf durchsehen, um Ihren Kommentar zu verstehen.
Mark Amery
2
Dies scheint irgendwie sinnlos zu sein, da ich niemals Dateien mit dem Namen "install" oder dergleichen in meiner Codebasis haben werde. Die meisten Dateien werden eine Dateierweiterung haben, und die Dateien ohne Dateierweiterung werden normalerweise in Großbuchstaben angezeigt, z. B. 'README'. Wenn Sie jedoch ein Bash-Skript mit dem Namen "install" anstelle von "install.sh" haben, werden Sie eine schlechte Zeit haben.
Nuklearflut
6
@JasonTu Dies ist nicht unbedingt wahr. Bei Bash-Scripting-Konventionen werden Sie aufgefordert, die Erweiterung .shoder .bashfür "Programme" wegzulassen, die so ausgeführt werden, als hätten sie eine Hauptfunktion, und das Hinzufügen einer Erweiterung für Bibliotheken, die Sie einschließen ( source mylib.sh). Tatsächlich kam ich zu dieser SO-Frage, weil ich ein Skript im selben Verzeichnis wie mein Makefile hatteinstall
Kyle
10
@ Kyle Ja, ich bin mir nicht sicher, was mein früheres Ich bedeutete. In diesen Tagen benutze ich die .PHONYganze Zeit ...
Nuklearflut
2
@JasonTu Die Lösung hier ist einfach: Bauen Sie eine Zeitmaschine und "ersetzen" Sie Ihr vergangenes Selbst. Ich empfehle, eine Schaufel mitzunehmen, damit niemand merkt, dass Sie die .PHONYVersion sind.
Mateen Ulhaq
120

HINWEIS : Das Make-Tool liest das Makefile und überprüft in einer Regel die Änderungszeitstempel der Dateien auf beiden Seiten des Symbols ':'.

Beispiel

In einem Verzeichnis 'test' sind folgende Dateien vorhanden:

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

In Makefile wird eine Regel wie folgt definiert:

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

Nehmen wir nun an, dass die Datei 'Hallo' eine Textdatei ist, die einige Daten enthält, die nach der Datei 'Hallo.c' erstellt wurden. Der Zeitstempel für die Änderung (oder Erstellung) von "Hallo" ist also neuer als der von "Hallo.c". Wenn wir also 'Hallo machen' über die Befehlszeile aufrufen, wird Folgendes gedruckt:

make: `hello' is up to date.

Greifen Sie jetzt auf die Datei 'hello.c' zu und fügen Sie einige Leerzeichen ein, die die Codesyntax oder -logik nicht beeinflussen. Speichern und beenden Sie sie dann. Jetzt ist der Änderungszeitstempel von hello.c neuer als der von 'hallo'. Wenn Sie nun 'Hallo machen' aufrufen, werden die Befehle wie folgt ausgeführt:

cc hello.c -o hello

Und die Datei 'Hallo' (Textdatei) wird mit einer neuen Binärdatei 'Hallo' (Ergebnis des obigen Kompilierungsbefehls) überschrieben.

Wenn wir .PHONY im Makefile wie folgt verwenden:

.PHONY:hello

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

Wenn Sie dann 'make hello' aufrufen, werden alle im pwd 'test' vorhandenen Dateien ignoriert und der Befehl jedes Mal ausgeführt.

Angenommen, für das Hallo-Ziel sind keine Abhängigkeiten deklariert:

hello:
    cc hello.c -o hello

und 'Hallo' Datei ist bereits im pwd 'Test' vorhanden, dann wird 'Hallo machen' immer angezeigt als:

make: `hello' is up to date.
Prerit Jain
quelle
3
Dies macht nicht nur die Befehle, die ich ausführe make, sinnvoll, sondern macht letztendlich auch insgesamt Sinn, es geht nur um die Dateien! Vielen Dank für diese Antwort.
Kzqai
80
.PHONY: install
  • bedeutet, dass das Wort "install" keinen Dateinamen in diesem Makefile darstellt;
  • bedeutet, dass das Makefile nichts mit einer Datei namens "install" im selben Verzeichnis zu tun hat.
YourBestBet
quelle
45

Es ist ein Build-Ziel, das kein Dateiname ist.

JohnMcG
quelle
33

Die beste Erklärung ist das GNU-Handbuch selbst: 4.6 Abschnitt "Falsche Ziele" .

.PHONYist einer der speziellen integrierten Zielnamen von make . Es gibt andere Ziele, an denen Sie interessiert sein könnten. Es lohnt sich daher, diese Referenzen durchzublättern.

Wenn es an der Zeit ist, ein .PHONY-Ziel zu berücksichtigen, führt make sein Rezept bedingungslos aus, unabhängig davon, ob eine Datei mit diesem Namen vorhanden ist oder wie lange sie zuletzt geändert wurde.

Möglicherweise interessieren Sie sich auch für die Standardziele von make wie allund clean.

James Wald
quelle
11

Es gibt auch einen wichtigen kniffligen Leckerbissen von ".PHONY" - wenn ein physisches Ziel von einem falschen Ziel abhängt, das von einem anderen physischen Ziel abhängt:

TARGET1 -> PHONY_FORWARDER1 -> PHONY_FORWARDER2 -> TARGET2

Sie würden einfach erwarten, dass TARGET1, wenn Sie TARGET2 aktualisiert haben, als veraltet gegenüber TARGET1 angesehen werden sollte, sodass TARGET1 neu erstellt werden sollte. Und so funktioniert es wirklich .

Der schwierige Teil ist, wenn TARGET2 gegen TARGET1 nicht veraltet ist. In diesem Fall sollten Sie damit rechnen, dass TARGET1 nicht neu erstellt werden sollte.

Dies funktioniert überraschenderweise nicht, weil: das falsche Ziel trotzdem ausgeführt wurde (wie es normalerweise bei falschen Zielen der Fall ist ) , was bedeutet, dass das falsche Ziel als aktualisiert angesehen wurde . Und aus diesem Grund gilt TARGET1 als abgestanden gegen das falsche Ziel .

Erwägen:

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

Sie können damit herumspielen:

  • Machen Sie zuerst 'vorbereiten', um die "Quelldateien" vorzubereiten
  • Spielen Sie damit herum, indem Sie bestimmte Dateien berühren, um sie aktualisiert zu sehen

Sie können sehen, dass fileall indirekt über ein falsches Ziel von file1 abhängt. Aufgrund dieser Abhängigkeit wird es jedoch immer neu erstellt . Wenn Sie die Abhängigkeit ändern in fileallvon filefwdzu file, jetzt fileallwird nicht jedes Mal wieder aufgebaut, aber nur dann , wenn alle abhängigen Ziele ist abgestanden dagegen als Datei.

Ethouris
quelle
5

Das spezielle Ziel .PHONY:ermöglicht es, falsche Ziele zu deklarieren, so dassmake nicht als tatsächliche Dateinamen überprüft werden. Es funktioniert immer, auch wenn solche Dateien noch vorhanden sind.

Sie können mehrere .PHONY:in Ihre Makefile:

.PHONY: all

all : prog1 prog2

...

.PHONY: clean distclean

clean :
    ...
distclean :
    ...

Es gibt eine andere Möglichkeit, falsche Ziele zu deklarieren: Setzen Sie einfach '::'

all :: prog1 prog2

...

clean ::
    ...
distclean ::
    ...

Das '::' hat eine besondere Bedeutung: Ziele sind falsch und können mehrmals vorkommen:

clean ::
    rm file1

...


clean ::
    rm file2

Die Befehlsblöcke werden nacheinander aufgerufen.

Edouard Thiel
quelle
3

Ich benutze sie oft, um dem Standardziel mitzuteilen, dass es nicht feuern soll.

superclean: clean andsomethingelse

blah: superclean

clean:
   @echo clean

%:
   @echo catcher $@

.PHONY: superclean

Ohne PHONY, make supercleanwürde Feuer clean, andsomethingelseund catcher superclean; aber mit PHONY make supercleanwird das nicht feuern catcher superclean.

Wir müssen uns keine Sorgen machen, dass wir das machen clean Ziel PHONY ist, weil es nicht ganz falsch ist. Obwohl die saubere Datei nie erstellt wird, müssen Befehle ausgelöst werden, sodass make den Eindruck erweckt, dass es sich um ein endgültiges Ziel handelt.

Das supercleanZiel ist jedoch wirklich falsch, daher wird make versuchen, es mit allem anderen zu stapeln, das Deps für das supercleanZiel bereitstellt - dies schließt andere supercleanZiele und das %Ziel ein.

Beachten Sie, dass wir überhaupt nichts über andsomethingelseoder sagen blah, also gehen sie eindeutig zum Fänger.

Die Ausgabe sieht ungefähr so ​​aus:

$ make clean
clean

$ make superclean
clean
catcher andsomethingelse

$ make blah 
clean
catcher andsomethingelse
catcher blah
Jettero
quelle