Определить переменную make во время выполнения правила - PullRequest
176 голосов
/ 15 декабря 2009

В моем GNUmakefile я хотел бы иметь правило, которое использует временный каталог. Например:

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

Как написано, приведенное выше правило создает временный каталог в то время, когда правило проанализировано . Это означает, что, даже если я не разглядываю .tar все время, создается много временных каталогов. Я бы не хотел, чтобы мои / tmp были завалены неиспользуемыми временными каталогами.

Есть ли способ заставить переменную быть определенной только при запуске правила, а не всякий раз, когда оно определено?

Моя основная мысль - сбросить mktemp и tar в сценарий оболочки, но это выглядит несколько неприглядно.

Ответы [ 3 ]

272 голосов
/ 15 декабря 2009

В вашем примере переменная TMP устанавливается (и создается временный каталог) всякий раз, когда оцениваются правила для out.tar. Чтобы создать каталог только тогда, когда out.tar действительно запущен, вам нужно переместить создание каталога вниз по шагам:

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

Функция eval оценивает строку, как если бы она была введена в make-файл вручную. В этом случае он устанавливает переменную TMP в результате вызова функции shell.

изменить (в ответ на комментарии):

Чтобы создать уникальную переменную, вы можете сделать следующее:

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

Это добавит имя цели (в данном случае out.tar) к переменной, создав переменную с именем out.tar_TMP. Надеюсь, этого достаточно для предотвращения конфликтов.

52 голосов
/ 16 марта 2015

Относительно простой способ сделать это - написать всю последовательность в виде сценария оболочки.

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

Здесь я собрал несколько советов: https://stackoverflow.com/a/29085684/86967

27 голосов
/ 21 декабря 2013

Другая возможность состоит в использовании отдельных строк для настройки переменных при запуске правила.

Например, вот make-файл с двумя правилами. Если правило срабатывает, оно создает временный каталог и устанавливает для TMP имя временного каталога.

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}

Запуск кода дает ожидаемый результат:

$ ls
Makefile
$ make ruleB
echo testruleB_Y4Ow
testruleB_Y4Ow
$ ls
Makefile  testruleB_Y4Ow
...