2009-12-15 9 views
132

En mi GNUmakefile, me gustaría tener una regla que use un directorio temporal. Por ejemplo:Defina la variable make en el tiempo de ejecución de la regla

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

Como está escrito, la regla anterior crea el directorio temporal en el momento que la regla es analizado sintácticamente . Esto significa que, incluso yo no distingo .tar todo el tiempo, muchos directorios temporales se crean. Me gustaría evitar que my/tmp esté lleno de directorios temporales no utilizados.

¿Hay alguna manera de hacer que la variable solo se defina cuando se dispara la regla, a diferencia de cuando se define?

Mi idea principal es volcar el mktemp y tar en un script de shell, pero eso parece un tanto antiestético.

Respuesta

206

En su ejemplo, se establece la variable TMP (y el directorio temporal creado) cada vez que se evalúan las reglas para out.tar. Con el fin de crear el directorio sólo cuando out.tar es en realidad despedido, tiene que mover la creación del directorio hacia abajo en los pasos:

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

La función eval evalúa una cadena como si hubiera sido escrito en el makefile manualmente. En este caso, establece la variable TMP en el resultado de la llamada a la función shell.

edición (en respuesta a los comentarios):

Para crear una variable única, se puede hacer lo siguiente:

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) 

Esto anteponer el nombre del objetivo (out.tar, en este caso) a la variable, produciendo una variable con el nombre out.tar_TMP. Con suerte, eso es suficiente para evitar conflictos.

+2

Geniales algunas aclaraciones ... esto no alcance TMP a este objetivo, ¿verdad? Entonces, si hay otras reglas que tienen su propio uso de $ (TMP) (posiblemente en paralelo con -j), puede haber conflictos? Además, ¿el @echo es incluso necesario? Parece que podrías dejarlo fuera. –

+0

No pensé que pudieras hacerlo sin el '@ echo', pero lo probé y funciona. ¡Buena atrapada! Lo cambiaré en mi respuesta. –

+0

En lo que respecta al alcance, la variable TMP no sería específica para esa regla en particular.Existiría en la protección de nombres global y podría entrar en conflicto con otras variables que tienen el mismo nombre. ¿Es ese el comportamiento deseado? Probablemente haya formas de evitarlo si es necesario. –

20

Otra posibilidad es utilizar líneas separadas para configurar las variables de creación cuando se dispara una regla.

Por ejemplo, aquí hay un archivo MAKE con dos reglas. Si una regla se activa, crea un directorio de temperatura y establece TMP en el nombre del directorio de la instalación.

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} 

ejecutar el código produce el resultado esperado:

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

Solo como recordatorio, GNU make tiene una sintaxis para [requisitos previos de pedido] (http://www.gnu.org/software/make/manual/make.html#Prerequisite-Types) que pueden ser necesarios para complementar esto enfoque. – anol

+3

¡Tenga cuidado con esta solución! 'ruleA: TMP = $ (shell mktemp -d testruleA_XXXX)' y 'ruleB: TMP = $ (shell mktemp -d testruleB_XXXX)' ocurrirá cuando se evalúe primero el Makefile. En otras palabras, 'ruleA: TMP = $ (shell ...' sucede antes de lo que piensas. Si bien esto podría funcionar para este caso particular, este método causará problemas para algunas operaciones secuenciales. – JamesThomasMoon1979

31

una manera relativamente fácil de hacer esto es escribir la secuencia entera como una secuencia de comandos shell.

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

he consolidado algunos consejos relacionados aquí: https://stackoverflow.com/a/29085684/86967

+2

Este es definitivamente el más simple y por lo tanto el mejor responda (evite '@' y 'eval' y haga el mismo trabajo). Tenga en cuenta que en su salida verá' $ TMP' (por ejemplo, 'tar-C $ TMP ...') aunque el valor se transfiere correctamente al comando –

+0

Así es como se hace normalmente, espero que la gente vea esta respuesta porque en la práctica nadie hace todo el esfuerzo del aceptado. – pmos

Cuestiones relacionadas