2009-12-15 4 views
132

In meiner GNUmakefile möchte ich eine Regel haben, die ein temporäres Verzeichnis verwendet. Zum Beispiel:Definiere make-Variable zur Ausführungszeit der Regel

out.tar: TMP := $(shell mktemp -d) 
     echo hi $(TMP)/hi.txt 
     tar -C $(TMP) cf [email protected] . 
     rm -rf $(TMP) 

Wie geschrieben, schafft die obige Regel das temporäre Verzeichnis zu der Zeit, die die Regel analysiert ist. Dies bedeutet, dass, selbst wenn ich nicht ständig out.tar mache, viele temporäre Verzeichnisse erstellt werden. Ich möchte vermeiden, dass mein/tmp mit ungenutzten temporären Verzeichnissen übersät ist.

Gibt es eine Möglichkeit, die Variable nur zu definieren, wenn die Regel ausgelöst wird, im Gegensatz zu wann immer sie definiert ist?

Mein Hauptgedanke ist es, die mktemp und tar in ein Shell-Skript zu dumpen, aber das scheint etwas unansehnlich.

Antwort

206

In Ihrem Beispiel die TMP Variable gesetzt ist (und das temporäre Verzeichnis erstellt), wenn die Regeln für out.tar ausgewertet werden. Um nur das Verzeichnis zu erstellen, wenn out.tar tatsächlich gefeuert, müssen Sie das Verzeichnis erstellen, um nach unten zu bewegen in die Stufen:

out.tar : 
    $(eval TMP := $(shell mktemp -d)) 
    @echo hi $(TMP)/hi.txt 
    tar -C $(TMP) cf [email protected] . 
    rm -rf $(TMP) 

Die eval Funktion eine Zeichenfolge auswertet, als ob es von Hand in die Make-Datei eingegeben worden war. In diesem Fall wird die Variable TMP auf das Ergebnis des Funktionsaufrufs shell gesetzt.

bearbeiten (in Reaktion auf die Kommentare):

eine eindeutige Variable zu erstellen, können Sie folgendes tun:

out.tar : 
    $(eval [email protected]_TMP := $(shell mktemp -d)) 
    @echo hi $([email protected]_TMP)/hi.txt 
    tar -C $([email protected]_TMP) cf [email protected] . 
    rm -rf $([email protected]_TMP) 

Dies ist der Name des Ziel prepend würde (out.tar, in diesem Fall) an die Variable, die eine Variable mit dem Namen out.tar_TMP erzeugt. Hoffentlich reicht das aus, um Konflikte zu verhindern.

+2

einige Präzisierungen cool ... das wird nicht Umfang TMP zu diesem Ziel wird es? Wenn es also andere Regeln gibt, die ihre eigene $ (TMP) -Nutzung haben (möglicherweise parallel zu -j), kann es zu Konflikten kommen? Ist das @echo überhaupt nötig? Scheint, du könntest es einfach weglassen. –

+0

Ich dachte nicht, du könntest es ohne das '@ echo' machen, aber ich habe es getestet und es funktioniert. Guter Fang! Ich werde es in meiner Antwort ändern. –

+0

Was das Scoping angeht, wäre die TMP-Variable nicht spezifisch für diese spezielle Regel.Es würde in der globalen Namesapce vorhanden sein und könnte Konflikte mit anderen Variablen mit demselben Namen verursachen. Ist das das gewünschte Verhalten? Es gibt wahrscheinlich Möglichkeiten, um es zu umgehen, wenn es sein muss. –

20

Eine andere Möglichkeit ist die Verwendung separater Zeilen zum Einrichten von Variablen, wenn eine Regel ausgelöst wird.

Zum Beispiel ist hier ein Makefile mit zwei Regeln. Wenn eine Regel ausgelöst wird, erstellt sie ein temporäres Verzeichnis und setzt TMP auf den Namen des temporären Verzeichnisses.

PHONY = ruleA ruleB display 

all: ruleA 

ruleA: TMP = $(shell mktemp -d testruleA_XXXX) 
ruleA: display 

ruleB: TMP = $(shell mktemp -d testruleB_XXXX) 
ruleB: display 

display: 
    echo ${TMP} 

Ausführen des Codes erzeugt das erwartete Ergebnis:

$ ls 
Makefile 
$ make ruleB 
echo testruleB_Y4Ow 
testruleB_Y4Ow 
$ ls 
Makefile testruleB_Y4Ow 
+0

Nur zur Erinnerung, GNU make hat eine Syntax für [nur Bestellvoraussetzungen] (http://www.gnu.org/software/make/manual/make.html#Prerequisite-Types), die notwendig sein könnte, um dies zu ergänzen Ansatz. – anol

+3

Vorsicht mit dieser Lösung! 'ruleA: TMP = $ (shell mktemp -d testruleA_XXXX)' und 'ruleB: TMP = $ (shell mktemp -d testruleB_XXXX)' wird passieren, wenn das Makefile zuerst ausgewertet wird. Mit anderen Worten, 'ruleA: TMP = $ (shell ...' geschieht früher als Sie denken. Während dies für diesen speziellen Fall funktionieren könnte, wird diese Methode bei einigen sequentiellen Operationen Probleme verursachen. – JamesThomasMoon1979

31

Eine relativ einfache Möglichkeit, dies zu tun, ist die gesamte Sequenz als ein Shell-Skript zu schreiben.

out.tar: 
    set -e ;\ 
    TMP=$$(mktemp -d) ;\ 
    echo hi $$TMP/hi.txt ;\ 
    tar -C $$TMP cf [email protected] . ;\ 
    rm -rf $$TMP ;\ 

Ich habe einige zugehörige Tipps hier konsolidiert: https://stackoverflow.com/a/29085684/86967

+2

Dies ist definitiv die einfachste und daher beste Antwort (Vermeiden Sie '@' und 'eval' und machen Sie den gleichen Job.) Beachten Sie, dass Sie in Ihrer Ausgabe' $ TMP' sehen (zB 'tar -C $ TMP ...'), obwohl der Wert korrekt an den Befehl übergeben wird –

+0

So wird es normalerweise gemacht, ich hoffe, die Leute sehen diese Antwort, weil in der Praxis niemand die ganze Anstrengung des Akzeptierten durchmacht. – pmos

Verwandte Themen