Definir make variable en tiempo de ejecución de la regla


En mi GNUmakefile, me gustaría tener una regla que utiliza un directorio temporal. Por ejemplo:

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

Tal como está escrito, la regla anterior crea el directorio temporal en el momento en que la regla se analiza . Esto significa que, ni siquiera yo lo hago.tar todo el tiempo, muchos directorios temporales se crean. Me gustaría evitar que mi /tmp esté lleno de directorios temporales no utilizados.

Hay una manera de hacer que la variable solo se defina cuando se dispara la regla, a diferencia de cada vez que se define?

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

Author: Emil Sit, 2009-12-15

3 answers

En su ejemplo, la variable TMP se establece (y el directorio temporal se crea) cada vez que se evalúan las reglas para out.tar. Para crear el directorio solo cuando out.tar está realmente activado, necesita 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 $@ .
    rm -rf $(TMP)

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

Editar (en respuesta a los comentarios):

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

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

Esto precedería el nombre del objetivo (out.tar, en este caso) a la variable, produciendo una variable con el nombre out.tar_TMP. Esperemos que eso sea suficiente para prevenir los conflictos.

 232
Author: e.James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-15 22:18:59

Una forma relativamente fácil de hacer esto es escribir toda la secuencia como un script de shell.

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

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

 37
Author: nobar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:43

Otra posibilidad es usar líneas separadas para configurar las variables Make cuando se dispara una regla.

Por ejemplo, aquí hay un makefile con dos reglas. Si una regla se dispara, crea un directorio temporal y establece TMP en el nombre del directorio temporal.

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
 23
Author: user3124434,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-21 01:32:21