В моем GNUmakefile я хотел бы иметь правило, которое использует временный каталог. Например:
out.tar: TMP := $(shell mktemp -d)
echo hi $(TMP)/hi.txt
tar -C $(TMP) cf $@ .
rm -rf $(TMP)
Как написано, приведенное выше правило создает временную директорию в то время, когда правило анализируется. Это означает, что даже я не делаю out.tar все время, создаются многие временные каталоги. Я бы хотел, чтобы мой /tmp был завален неиспользуемыми временными каталогами.
Есть ли способ заставить переменную определять только при запуске правила, в отличие от всякий раз, когда он определен?
Моя основная мысль - выгрузить mktemp и tar в оболочку script, но это кажется несколько неприглядным.
Ответ 1
В вашем примере переменная 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
. Надеюсь, этого достаточно, чтобы предотвратить конфликты.
Ответ 2
Относительно простой способ сделать это - написать всю последовательность в виде оболочки script.
out.tar:
set -e ;\
TMP=$$(mktemp -d) ;\
echo hi $$TMP/hi.txt ;\
tar -C $$TMP cf $@ . ;\
rm -rf $$TMP ;\
Я собрал несколько связанных советов здесь: fooobar.com/questions/41289/...
Ответ 3
Другая возможность заключается в использовании отдельных строк для настройки переменных Make при возникновении правила.
Например, вот make файл с двумя правилами. Если правило срабатывает, оно создает временный каталог и устанавливает TMP для имени temp dir.
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
Ответ 4
Мне не нравятся ответы "Не", но... нет.
Переменные make
являются глобальными и должны оцениваться на этапе "разбора" make файла, а не на этапе выполнения.
В этом случае, если переменная локальна для одной цели, следуйте @nobar answer и сделайте ее переменной оболочки.
Целевые переменные также считаются вредоносными в других реализациях make: kati, Mozilla pymake. Из-за них цель может быть построена по-разному в зависимости от того, была ли она построена автономно, или как зависимость родительской цели с переменной, специфичной для цели. И ты не узнаешь, как это было, потому что не знаешь, что уже построено.