Wie erzwingen Sie ein Makefile, um ein Ziel neu zu erstellen?

182

Ich habe ein Makefile, das ein anderes Makefile erstellt und dann aufruft. Da dieses Makefile mehr Makefiles aufruft, die die Arbeit erledigen, ändert es sich nicht wirklich. Daher wird immer daran gedacht, dass das Projekt erstellt und auf dem neuesten Stand ist.

dnetdev11 ~ # make
make: `release' is up to date.

Wie zwinge ich das Makefile, das Ziel neu zu erstellen?

clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean


build = svn up ~/xxx                                                       \
        $(clean)                                                                \
        ~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace        \
        $(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1)                    \


release:
        $(build )

debug:
        $(build DEBUG=1)

clean:
        $(clean)

install:
        cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin
        cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib

Hinweis: Namen wurden entfernt, um die Unschuldigen zu schützen

Edit: Final Fixed version:

clean = $(MAKE) -f xxx_compile.workspace.mak clean;


build = svn up;                                         \
        $(clean)                                        \
        ./cbp2mak/cbp2mak -C . xxx_compile.workspace;   \
        $(MAKE) -f xxx_compile.workspace.mak    $(1);   \


.PHONY: release debug clean install

release:
        $(call build,)

debug:
        $(call build,DEBUG=1)

clean:
        $(clean)

install:
        cp ./source/xxx_utillity/release/xxx_util /usr/bin
        cp ./dlls/Release/xxxcore.so /usr/lib
Lodle
quelle
Lodle, da dies eine häufig besuchte Frage ist, möchten Sie die Frage so bearbeiten, dass sie moderner ist? (Es sieht so aus, .PHONYals wäre es nicht Ihr einziges Problem, und Sie sollten die Lösung nicht wirklich in die Frage einarbeiten oder zumindest nicht mehr.)
Keith M

Antworten:

22

Sie können eines oder mehrere Ihrer Ziele als falsch deklarieren .

Ein falsches Ziel ist eines, das nicht wirklich der Name einer Datei ist. Vielmehr ist es nur ein Name für ein Rezept, das ausgeführt werden soll, wenn Sie eine explizite Anfrage stellen. Es gibt zwei Gründe, ein falsches Ziel zu verwenden: einen Konflikt mit einer gleichnamigen Datei zu vermeiden und die Leistung zu verbessern.

...

Ein falsches Ziel sollte keine Voraussetzung für eine echte Zieldatei sein. Wenn dies der Fall ist, wird das Rezept jedes Mal ausgeführt, wenn make diese Datei aktualisiert. Solange ein falsches Ziel niemals eine Voraussetzung für ein echtes Ziel ist, wird das falsche Zielrezept nur ausgeführt, wenn das falsche Ziel ein bestimmtes Ziel ist

Dave
quelle
68
Diese Antwort ist, obwohl sie "akzeptiert" und hoch "hochgestuft" ist, wirklich falsch. Zuerst heißt es "Ziele als falsch deklarieren", dann heißt es "Falsches Ziel ist nicht wirklich der Name einer Datei". Wenn Ihr Ziel eine Datei ist, ist dies ein Widerspruch in der Antwort. Zweitens heißt es "falsches Ziel sollte keine Voraussetzung für ein echtes sein" - nun, was ist, wenn es ist? In der ursprünglichen Frage wurde nicht angegeben, ob dies der Fall ist oder nicht. Die richtige Antwort ist, nicht zu erklären , Ihre Ziele unecht zu sein, sondern vielmehr ein zusätzliches Pseudoziel erklären, und dann hängt die Ziele , die Sie wieder aufgebaut werden sollen, auf dass.
Mark Galeck
2
@ MarkGaleck. Wenn die Antwort besagt, dass "Ein falsches Ziel eines ist, das nicht wirklich der Name einer Datei ist", wird direkt aus dem Handbuch gcc make zitiert. Es ist vollkommen richtig.
Drlolly
"Ziel" ist ein Make-Begriff, der sich auf den Text links von einem Doppelpunkt bezieht :, nicht nur auf das Endergebnis, das Sie erstellen möchten (z. B. Ihre Binärdatei). In der Frage, release, debug, clean, und installsind die Make - Ziele, nicht xxx_utiloder xxxcore.sooder irgendetwas anderes.
Keith M
727

Der zu -Bmachende Schalter, dessen lange Form ist --always-make, weist makean, Zeitstempel zu ignorieren und die angegebenen Ziele zu setzen. Dies kann den Zweck der Verwendung von make zunichte machen, aber es kann das sein, was Sie brauchen.

Sykora
quelle
4
@ MarkKCowan Ich stimme vollkommen zu! Diese Option ist genau das, wonach ich gesucht habe, nicht irgendein Workaround-Hack, wie Dave vorschlägt.
Maarten Bamelis
8
Die Einschränkung bei diesem Ansatz ist, dass nur zu viele Dinge aufgebaut werden. Speziell mit Autotools habe ich gesehen, wie es erneut konfiguriert wurde. Ich wünschte, eine LD_PRELOAD-basierte Lösung könnte erstellt werden !!
vrdhn
Ja, und es kann sogar Dateien umschreiben, die Sie nicht wollten! wie globale Systembibliotheken, die in den Abhängigkeiten erscheinen und neu erstellt und überschrieben werden ...
Julio Guerra
18

Ein Trick, für den früher in einem Sun-Handbuch dokumentiert wurde, makeist die Verwendung eines (nicht vorhandenen) Ziels '.FORCE'. Sie können dies tun, indem Sie eine Datei force.mk erstellen, die Folgendes enthält:

.FORCE:
$(FORCE_DEPS): .FORCE

Angenommen, Ihr vorhandenes Makefile wird aufgerufen makefile, können Sie Folgendes ausführen:

make FORCE_DEPS=release -f force.mk -f makefile release

Da .FORCEes nichts gibt, ist alles, was davon abhängt, veraltet und wird neu aufgebaut.

All dies funktioniert mit jeder Version von make; Unter Linux haben Sie GNU Make und können daher das .PHONY-Ziel wie beschrieben verwenden.

Es ist auch erwägenswert, warum makedie Veröffentlichung als aktuell angesehen wird. Dies kann daran liegen, dass Sie einen touch releaseBefehl unter den ausgeführten Befehlen haben. Dies kann daran liegen, dass eine Datei oder ein Verzeichnis mit dem Namen "release" vorhanden ist, keine Abhängigkeiten aufweist und daher auf dem neuesten Stand ist. Dann gibt es den eigentlichen Grund ...

Jonathan Leffler
quelle
14

Jemand anderes schlug vor .PHONY, was definitiv richtig ist. .PHONY sollte für jede Regel verwendet werden, für die ein Datumsvergleich zwischen Eingabe und Ausgabe ungültig ist. Da hast du keine Ziele des Formularsoutput: input , sollten Sie .PHONY für ALLE verwenden!

Trotzdem sollten Sie wahrscheinlich einige Variablen oben in Ihrem Makefile für die verschiedenen Dateinamen definieren und echte Make-Regeln definieren, die sowohl Eingabe- als auch Ausgabeabschnitte enthalten, damit Sie die Vorteile von make nutzen können, nämlich, dass Sie nur tatsächlich kompilieren Dinge, die notwendig sind, um zu kopieren!

Bearbeiten: Beispiel hinzugefügt. Ungetestet, aber so machen Sie .PHONY

.PHONY: clean    
clean:
    $(clean)
Staffelei
quelle
1
Wenn Sie mir ein Beispiel zeigen könnten, wäre es schön.
Atm ich hacke
1
Der Ort des .PHONYZiels spielt keine Rolle. Es kann überall in der sein Makefile.
Adrian W
5

Wenn ich mich richtig erinnere, verwendet 'make' Zeitstempel (Änderungszeit der Datei), um festzustellen, ob ein Ziel aktuell ist oder nicht. Eine übliche Methode, um eine Neuerstellung zu erzwingen, besteht darin, diesen Zeitstempel mit dem Befehl 'touch' zu aktualisieren. Sie können versuchen, 'touch' in Ihrem Makefile aufzurufen, um den Zeitstempel eines der Ziele (möglicherweise eines dieser Sub-Makefiles) zu aktualisieren, wodurch Make möglicherweise gezwungen wird, diesen Befehl auszuführen.

Poundifdef
quelle
5

Diese einfache Technik ermöglicht es dem Makefile, normal zu funktionieren, wenn kein Forcen gewünscht wird. Erstellen Sie am Ende Ihres Makefiles ein neues Ziel namens force . Das Force- Ziel berührt eine Datei, von der Ihr Standardziel abhängt. Im folgenden Beispiel habe ich touch myprogram.cpp hinzugefügt . Ich habe auch einen rekursiven Aufruf hinzugefügt zu machen . Dies führt dazu, dass das Standardziel jedes Mal festgelegt wird, wenn Sie make force eingeben .

yourProgram: yourProgram.cpp
       g++ -o yourProgram yourProgram.cpp 

force:
       touch yourProgram.cpp
       make
groko
quelle
3

Ich habe es versucht und es hat bei mir funktioniert

Fügen Sie diese Zeilen zu Makefile hinzu

clean:
    rm *.o output

new: clean
    $(MAKE)     #use variable $(MAKE) instead of make to get recursive make calls

speichern und jetzt anrufen

make new 

und es wird alles wieder neu kompilieren

Was ist passiert?

1) 'neue' Anrufe sauber. 'clean' do 'rm' entfernt alle Objektdateien mit der Erweiterung '.o'.

2) 'neue' Anrufe 'machen'. 'make' stellt sicher, dass keine '.o'-Dateien vorhanden sind, sodass alle' .o 'erneut erstellt werden. Dann verknüpft der Linker die gesamte O-Datei mit einer ausführbaren Ausgabe

Viel Glück

hamaney
quelle
1
Im Rezept für eine newbessere Verwendung $(MAKE)alsmake
Basile Starynkevitch
1

Gemäß Millers rekursivem Make als schädlich sollten Sie einen Anruf vermeiden$(MAKE) ! In dem Fall, den Sie zeigen, ist es harmlos, da dies nicht wirklich ein Makefile ist, sondern nur ein Wrapper-Skript, das genauso gut in Shell geschrieben worden sein könnte. Aber Sie sagen, dass Sie bei tieferen Rekursionsstufen so weitermachen, also sind Sie wahrscheinlich auf die Probleme gestoßen, die in diesem augenöffnenden Aufsatz gezeigt werden.

Natürlich ist es mit GNU umständlich zu vermeiden. Und obwohl sie sich dieses Problems bewusst sind, ist es ihre dokumentierte Art, Dinge zu tun.

OTOH, makepp wurde als Lösung für dieses Problem erstellt. Sie können Ihre Makefiles auf Verzeichnisebene schreiben, sie werden jedoch alle zu einer vollständigen Ansicht Ihres Projekts zusammengefasst.

Legacy-Makefiles werden jedoch rekursiv geschrieben. Es gibt also eine $(MAKE)Problemumgehung, bei der nur die Unteranforderungen an den Haupt-Makepp-Prozess zurückgeleitet werden. Nur wenn Sie redundante oder, schlimmer noch, widersprüchliche Dinge zwischen Ihren Submakes tun, müssen Sie dies anfordern --traditional-recursive-make(was natürlich diesen Vorteil von makepp bricht). Ich kenne Ihre anderen Makefiles nicht, aber wenn sie sauber geschrieben sind, sollten mit makepp notwendige Neuerstellungen automatisch erfolgen, ohne dass hier von anderen vorgeschlagene Hacks erforderlich sind.

Daniel
quelle
Beantwortete die Frage nicht: Tangente an den Hauptpunkt und sollte ein Kommentar sein, keine Antwort.
Flungo
Vielleicht war ich nicht klar genug. Mit makepp wird dieses ganze Wrapper-Makefile nicht benötigt. Wenn Sie die genauen Abhängigkeiten kennen (alle, nicht nur die nachstehend aufgeführten :), wird es bei Bedarf immer neu erstellt.
Daniel
1

Wenn Sie keine der bereits erfolgreich kompilierten Ausgaben beibehalten müssen

nmake /A 

baut alle wieder auf

CZahrobsky
quelle
0

Es hängt tatsächlich davon ab, was das Ziel ist. Wenn es sich um ein falsches Ziel handelt (dh das Ziel ist NICHT mit einer Datei verbunden), sollten Sie es als .PHONY deklarieren.

Wenn das Ziel jedoch kein falsches Ziel ist, sondern es nur aus irgendeinem Grund neu erstellen möchte (ein Beispiel ist die Verwendung des Vorverarbeitungsmakros __TIME__), sollten Sie das in den Antworten hier beschriebene FORCE-Schema verwenden.

Kostas
quelle
0

Es wurde bereits erwähnt, dachte aber, ich könnte zur Verwendung hinzufügen touch

Wenn Sie touchalle zu kompilierenden Quelldateien haben, touchändert der Befehl die Zeitstempel einer Datei in die Systemzeit, zu der der touchBefehl ausgeführt wurde.

Der Zeitstempel der Quelldatei ist was make verwendet, um zu "wissen", dass sich eine Datei geändert hat und neu kompiliert werden muss

Beispiel: Wenn das Projekt ein C ++ - Projekt war, führen Sie es aus touch *.cpp, führen Sie es makeerneut aus, und make sollte das gesamte Projekt neu kompilieren.

mrflash818
quelle
0

make clean löscht alle bereits kompilierten Objektdateien.

Hanan Shteingart
quelle
0

Wie abernier betonte, gibt es im GNU-Handbuch eine empfohlene Lösung, bei der ein "falsches" Ziel verwendet wird, um den Wiederaufbau eines Ziels zu erzwingen:

clean: FORCE
        rm $(objects)
FORCE: ; 

Dies wird unabhängig von anderen Abhängigkeiten sauber ausgeführt.

Ich habe der Lösung aus dem Handbuch das Semikolon hinzugefügt, andernfalls ist eine leere Zeile erforderlich.

tdietel
quelle
-1

Auf meinem Linux-System (Centos 6.2) gibt es einen signifikanten Unterschied zwischen dem Deklarieren des Ziels .PHONY und dem Erstellen einer gefälschten Abhängigkeit von FORCE, wenn die Regel tatsächlich eine Datei erstellt, die dem Ziel entspricht. Wenn die Datei jedes Mal neu generiert werden muss, ist sowohl die gefälschte Abhängigkeit FORCE für die Datei als auch .PHONY für die gefälschte Abhängigkeit erforderlich.

falsch:

date > $@

richtig:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE
OnkelBob
quelle