2016-04-28 5 views
0

Wie vermitteln ich an make, dass ein Skript eine Datei bedingt ändern kann, so dass make wartet auf stat alle Dateien, bis dieses Skript ausgeführt wird?Makefile mit bedingt generierten Datei


Betrachten Sie das folgende Beispiel Spielzeug Reihe von Dateien:

// version 
2 
// foo.h - note the space between the 1 and the semicolon 
static constexpr int VERSION = 1 ; 
//update.py 
import sys 

with open(sys.argv[1]) as f: 
    cur = int(f.readlines()[0].split()[5]) 

with open('version') as f: 
    exp = int(f.readlines()[0].strip()) 

if cur < exp: 
    with open(sys.argv[1], 'w') as f: 
     print >> f, 'static constexpr int VERSION = {} ;'.format(exp) 
// main.cxx 
#include "foo.h" 
#include <iostream> 

int main() { 
    std::cout << VERSION << std::endl; 
} 
// makefile 
all : a.out updater 

a.out : main.o 
    g++ -o a.out main.o 

main.o : main.cxx 
    g++ -std=c++11 -o main.o -c main.cxx -MP -MMD -MF main.d 

.PHONY : updater 
updater : 
    python update.py foo.h 

-include main.d 

Die hier Absicht ist, dass ich eine Datei haben, foo.h, die bedingt ist durch ein Skript aktualisiert, update.py (wenn Sie die Nummer in version erhöhen, wird foo.h aktualisiert werden - sonst wird nichts passieren). Ich möchte diesen Begriff zu make irgendwie vermitteln - dass es nicht zu statfoo.h ist, um zu bestimmen, ob es main.o bis update.py Fertigstellen neu zu beenden braucht. Wie stelle ich die Bestellung sicher?

Hinweis: version Hier ist einfach ein Platzhalter für eine komplexe Reihe von Voraussetzungen, die nicht einfach zu äußern sind. Einfach hinzufügen foo.h : version ist keine Lösung.

+1

'foo.h: Updater' vielleicht? Oder mach einfach das Rezept für "Updater" das Rezept für "foo.h". – user657267

+0

@ user657267 Das funktioniert nicht. – Barry

+0

Leider habe ich mich geirrt, das Rezept in 'foo.h' zu verschieben, aber' foo.h' sollte das Ziel von 'main.o' und' updater' das Ziel von 'foo.h' sein. – user657267

Antwort

1

Erstens, wenn Sie zu aktualisieren, machen Sie nicht möchten, main.o usw. bis nach foo.h wurde aktualisiert Sie haben foo.h als Voraussetzung zur Liste:

main.o : main.cxx foo.h 
     g++ -std=c++11 -o main.o -c main.cxx -MP -MMD -MF main.d 

(Altho igitt natürlich würde ich nie es wie schreiben, habe ich immer Variablen wie folgt verwenden würde:

CXX = g++ 
CXXFLAGS = -std=c++11 
DEPFLAGS = -MP -MMD -MF $*.d 

main.o : main.cxx foo.h 
     $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(DEPFLAGS) -o [email protected] -c $< 

aber das ist mir ...)

Zweitens haben Sie eine Regel müssen foo.h zu aktualisieren. Wie Sie vorschlagen, sollte es sein .PHONY so ist es immer laufen, auch wenn es nicht immer foo.h nicht aktualisiert:

.PHONY: updater 
updater: 
     python update.py foo.h 

Nun müssen Sie diese beiden Regeln verbinden, so dass Sie eine Regel erstellen, die foo.h Links zu updater:

foo.h : updater ; 

Hinweis hier das Semikolon, dass kritische ist. Die Art, wie es funktioniert, ist dies: updater ist falsch, also wird es immer laufen, und das bedeutet, dass jedes Ziel, das davon abhängt, immer ausgeführt wird.So klar können Sie nicht main.o : main.cxx updater als main.o jedes Mal wieder auflisten.

Sie können also eine Zwischenregel einführen, foo.h : updater. Sie müssen dies trotzdem tun, da Sie foo.h als Voraussetzung angeben müssen, so dass Sie ein Ziel benötigen, um es zu bauen.

selbst jedoch wird dies nicht helfen, weil make sieht, dass es kein Rezept ist foo.h zu bauen, so dass es nicht erkennen, dass, wenn updater ausgeführt wurde es foo.h gebaut. Sie umgehen dies, indem Sie ein leeres Rezept für foo.h erstellen; das ist, was die ; ist für:

foo.h : updater ; 

, die für dieses Ziel foo.h ein leeres Rezept erstellt, und das ist genug, um zu überprüfen, um zu sehen, ob die Datei foo.h modifiziert wurde oder nicht. Wenn es geändert wird (durch updater), wird main.o neu erstellt. Wenn es nicht geändert wird, wird main.o nicht neu erstellt (es sei denn, es gibt einen anderen Grund, es neu zu erstellen).

+0

Ein Semikolon macht den Unterschied! Sie können den ersten Teil der Antwort entfernen, die Voraussetzung von 'foo.h' wird von' -include main.d' behandelt. – Barry

+0

Das ist nicht gut genug für generierte Dateien, weil das erste Mal 'make' nicht ausgeführt wird seien Sie irgendwelche '.d' Dateien, so dass make nicht wissen wird, dass irgendetwas von' foo.h' abhängt, also wird 'foo.h' nicht erstellt, dann erhalten Sie einen Kompilierungsfehler, der versucht, den ersten zu kompilieren und zu bauen '.d' Dateien. Es sei denn du sagst, dass 'foo.h' immer existiert, aber auch automatisch aktualisiert werden kann ...? Das ist ein bisschen ... seltsam ... Leute, die SCM-Systeme benutzen, möchten nicht automatisch automatisch aktualisierte Dateien einchecken. Auch dann wird es nicht versuchen, 'foo.h' das erste Mal zu aktualisieren. – MadScientist

+0

Das ist ein sehr guter Punkt, danke. – Barry

2

Wenn Sie main.o und a.out wenn und nur neu erstellen möchten, wenn das Skript foo.h ändert, könnte dies eine Aufgabe für rekursiv zu machen sein:

all : updater 
    @$(MAKE) a.out      

... 

main.o : main.cxx foo.h 
    ... 
+0

Das funktioniert (+1), aber ich möchte rekursive make hier vermeiden. – Barry