2009-12-15 12 views
132

Nel mio GNUmakefile, vorrei avere una regola che usi una directory temporanea. Per esempio:Definisci make variable al tempo di esecuzione della regola

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

Come scritto, la regola di cui sopra crea la directory temporanea nel momento in cui la regola è analizzato. Ciò significa che, anche se non lo faccio fuori.tar sempre, vengono create molte directory temporanee. Vorrei evitare che il mio/tmp sia disseminato di directory temporanee inutilizzate.

C'è un modo per far sì che la variabile venga definita solo quando la regola viene attivata, al contrario di quando viene definita?

Il mio pensiero principale è quello di scaricare mktemp e tar in uno script di shell, ma ciò sembra un po 'sgradevole.

risposta

206

Nel tuo esempio, la variabile TMP è impostato (e la directory temporanea creata) ogni volta che le regole per out.tar vengono valutati. Al fine di creare la directory solo quando out.tar è in realtà sparato, è necessario spostare la creazione di directory giù nelle fasi:

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

La funzione eval valuta una stringa come se fosse stato digitato nel makefile manualmente. In questo caso, imposta la variabile TMP sul risultato della chiamata di funzione shell.

modifica (in risposta ai commenti):

Per creare una variabile unico, si potrebbe procedere come segue:

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) 

Ciò anteporre il nome della destinazione (out.tar, in questo caso) alla variabile, producendo una variabile con il nome out.tar_TMP. Si spera che sia sufficiente per prevenire i conflitti.

+2

raffreddare un paio di chiarimenti ... questo non sarà portata TMP a questo obiettivo, sarà vero? Quindi se ci sono altre regole che hanno il loro uso $ (TMP) (possibilmente in parallelo con -j), ci possono essere conflitti? Inoltre, anche @echo è necessario? Sembra che potresti lasciarlo fuori. –

+0

Non pensavo che potessi farlo senza '@ echo', ma l'ho testato e funziona. Buona pesca! Lo cambierò nella mia risposta. –

+0

Per quanto riguarda lo scoping, la variabile TMP non sarebbe specifica per quella particolare regola.Sarebbe esistere nella namesapce globale e potrebbe entrare in conflitto con altre variabili che hanno lo stesso nome. È questo il comportamento desiderato? Ci sono probabilmente dei modi per aggirarlo se necessario. –

20

Un'altra possibilità è utilizzare righe separate per impostare Crea variabili quando viene attivata una regola.

Ad esempio, ecco un makefile con due regole. Se una regola viene attivata, crea una directory temporanea e imposta TMP sul nome della directory temporanea.

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} 

L'esecuzione del codice produce il risultato atteso:

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

Proprio come un promemoria, GNU make ha una sintassi per [prerequisiti solo dell'ordine] (http://www.gnu.org/software/make/manual/make.html#Prerequisite-Types) che potrebbe essere necessario per completare questo approccio. – anol

+3

Attenzione a questa soluzione! 'ruleA: TMP = $ (shell mktemp -d testruleA_XXXX)' e 'ruleB: TMP = $ (shell mktemp -d testruleB_XXXX)' avverrà quando il Makefile viene valutato per la prima volta. In altre parole, 'ruleA: TMP = $ (shell ...' succede prima di quanto pensiate.Questo potrebbe funzionare in questo caso particolare, questo metodo causerà problemi per alcune operazioni sequenziali. – JamesThomasMoon1979

31

un modo relativamente facile per farlo è quello di scrivere l'intera sequenza come uno script di shell.

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

ho consolidato alcuni suggerimenti relativi qui: https://stackoverflow.com/a/29085684/86967

+2

Questo è sicuramente il più semplice e quindi il migliore risposta (evitando '@' e 'eval' e facendo lo stesso lavoro). Si noti che nel proprio output si vede' $ TMP' (ad esempio 'tar -C $ TMP ...') sebbene il valore sia passato correttamente al comando –

+0

Ecco come si fa normalmente, spero che la gente veda questa risposta perché in pratica nessuno passa attraverso tutti gli sforzi di quello accettato. – pmos