2009-02-26 6 views
11

ich eine etwas hackish Make-Datei für die Ausführung von Tests haben:Warum machen GNU eine Datei löschen

### Run the tests 

tests := tests/test1 tests/test2 ... 

test: $(tests) 

$(tests): %: %.c 
    gcc -o [email protected] $(testflags) $< 
    [email protected] 

Es funktioniert, aber es macht etwas Make tun habe ich es noch nie gesehen tun. Mein Test ist derzeit defekt und verursacht einen Busfehler. Machen Sie gibt die folgende Ausgabe:

gcc -o tests/test1 [flags blah blah] tests/test1.c 
tests/test1 
make: *** [tests/test1] Bus error 
make: *** Deleting file `tests/test1' 

Ich bin gespannt auf die letzte Zeile. Das habe ich noch nie gesehen. Warum löscht Make den kompilierten Test?

Hinweis: Ich habe dieses Beispiel ziemlich stark bearbeitet, um es einfacher zu machen. Ich könnte einige Fehler eingeführt haben.

Antwort

14

Da das Ziel möglicherweise nicht korrekt erstellt wurde. Das nächste Mal, wenn Sie das Projekt make starten, wird es versuchen, das Ziel neu zu erstellen. Wenn die Datei nicht entfernt worden wäre, hätte make keine Möglichkeit zu wissen, dass etwas schief gelaufen ist. make kann nicht wissen, dass der Fehler von einem Test stammt und nicht vom Prozess, der das Ziel erstellt.


Ob dieses Verhalten in Ihrem Fall wünschenswert ist, hängt von der Art der Tests. Wenn Sie vorhaben, den Test so zu reparieren, dass er keine Bus error verursacht, ist das Entfernen des Ziels keine große Sache. Wenn Sie das Ziel später zum Debuggen verwenden möchten, müssen Sie den Erstellungsprozess ändern.

Eine Möglichkeit, Ziele nicht zu löschen, ist die Verwendung des Ziels .PRECIOUS.


Ein weiterer könnte sein:

$(tests): %: %.c 
    gcc -o [email protected] $(testflags) $< 
    [email protected] 

Nicht getestet, aber die documentation zeigt das Ziel nicht entfernt werden:

Wenn ein Fehler, dass make passiert hat, zu ignorieren nicht erklärt worden, Es impliziert, dass das aktuelle Ziel nicht korrekt wiederhergestellt werden kann, und auch kein anderes, das direkt oder indirekt davon abhängt. Für diese Ziele werden keine weiteren Befehle ausgeführt, da ihre Voraussetzungen nicht erreicht wurden.

und:

Normalerweise, wenn ein Befehl fehlschlägt, wenn er die Zieldatei überhaupt geändert hat, die Datei beschädigt ist und nicht verwendet-werden kann oder zumindest ist es nicht vollständig aktualisiert. Der Zeitstempel der Datei besagt jedoch, dass sie jetzt auf dem neuesten Stand ist. Wenn Sie also das nächste Mal make ausführen, wird nicht versucht, diese Datei zu aktualisieren. Die Situation ist genau so, wie wenn der Befehl durch ein Signal getötet wird; siehe Interrupts. Daher ist es im Allgemeinen das Richtige, die Zieldatei zu löschen, wenn der Befehl nach dem Ändern der Datei fehlschlägt. make wird dies tun, wenn .DELETE_ON_ERROR als Ziel angezeigt wird. Das ist fast immer das, was Sie machen wollen, aber es ist keine historische Praxis; Aus Gründen der Kompatibilität müssen Sie dies explizit anfordern.

11

Eine Möglichkeit, dieses Verhalten zu vermeiden, ist die Build und Testausführung in zwei Schritte aufgeteilt:

tests := tests/test1 tests/test2 ... 

test: $(tests) runtests 

$(tests): %: %.c 
    gcc -o [email protected] $(testflags) $< 

runtests: %.out: % 
    $< | tee [email protected] 

(Es gibt wahrscheinlich Fehler in meiner Make-Syntax, jemand fühlen Sie sich frei, sie zu korrigieren.) Die generelle Idee ist, dass der Testlauf eine Ausgabedatei erzeugt, die es einfacher macht, jeden Test einzeln auszuführen.

+1

+1 für die einzige Antwort, um darauf hinzuweisen, dass das Verhalten von einem fehlerhaften Makefile verursacht wurde, das das Generieren des Testprogramms kombinierte und es in einer einzigen Regel ausgeführt wurde. –

+0

IMO das ist die bessere Lösung: sauberer und mehr "make-like". Obwohl die Details sauberer behandelt werden könnten. Zuerst muss der Makefile-Autor entscheiden: Möchten Sie die Tests immer ausführen oder nur die Tests ausführen, wenn die Testdatei neu erstellt wurde (letzteres entspricht dem ursprünglichen Beispiel). – MadScientist

6

Dies ist das Standardverhalten von make. Wenn ein Befehl einen Fehlercode (z. B. eine Rückgabe ungleich Null) zurückgibt, wird das Make-Ziel gelöscht. Die Makefile-Direktiven .PRECIOUS und .IGNORE können dieses Verhalten ändern.

Verwandte Themen