Answers:
在您的示例中,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,如果它已经手动键入到makefile文件函数计算的字符串。在这种情况下,它将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
。希望这足以防止冲突。
$(eval $@_TMP := $(shell mktemp -d))
第一次评估Makefile时,将发生错误,而不是按照规则过程的顺序进行。换句话说,$(eval ...)
发生比您想象的要早。尽管对于此示例来说可以,但是此方法将导致某些顺序操作出现问题。
一个相对简单的方法是将整个序列编写为Shell脚本。
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
@
与eval
和做同样的工作)。请注意,尽管该值正确传递给了命令,但您在输出中会看到$TMP
(例如tar -C $TMP ...
)。
SHELL := /bin/bash
在makefile中启用特定于BASH的功能。
另一种可能性是在规则触发时使用单独的行来设置Make变量。
例如,这是带有两个规则的makefile。如果规则触发,它将创建一个临时目录并将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
ruleA: TMP = $(shell mktemp -d testruleA_XXXX)
并且ruleB: TMP = $(shell mktemp -d testruleB_XXXX)
会在首次评估Makefile时发生。换句话说,ruleA: TMP = $(shell ...
发生比您想象的要早。尽管这可能适用于此特定情况,但此方法将对某些顺序操作造成问题。
我不喜欢“不要”的答案,但是...不。
make
的变量是全局变量,应该在makefile的“解析”阶段而不是执行阶段进行评估。
在这种情况下,只要变量是单个目标的局部变量,请遵循@nobar的答案并将其设置为shell变量。
特定于目标的变量也被其他make实现视为有害:kati,Mozilla pymake。由于这些原因,可以根据是独立构建目标还是将其作为具有特定于目标的变量的父目标的依赖项来构建不同的目标。而且您将不知道它是哪种方式,因为您不知道已经构建了什么。