在规则执行时定义make变量

在我的GNUmakefile中,我希望有一个使用临时目录的规则。例如:

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

如上所述,上述规则在规则为解析时创建临时目录。这意味着,即使我不是一直创建out.tar,也会创建许多临时目录。我希望避免我的/tmp被未使用的临时目录所充斥。

是否有一种方法可以使变量仅在触发规则时定义,而不是在定义时定义?

我的主要想法是将mktemp和tar转储到shell脚本中,但这似乎有点不美观。

219985 次浏览

在你的例子中,每当计算out.tar规则时,就会设置TMP变量(并创建临时目录)。为了只在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的变量。希望这足以防止冲突。

另一种可能是在触发规则时使用单独的行来设置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

一种相对简单的方法是将整个序列作为shell脚本编写。

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

我在这里合并了一些相关的技巧

我不喜欢"不"的回答,但是…不喜欢。

make的变量是全局的,应该在makefile的“解析”阶段计算,而不是在执行阶段。

在这种情况下,只要变量是单个目标的局部变量,就遵循@nobar的回答并使其成为shell变量。

其他make实现也认为特定于目标的变量是有害的:卡蒂·Mozilla pymake。因此,可以根据目标是独立构建的,还是作为带有特定于目标变量的父目标的依赖项构建。你也不知道是哪条路,因为你不知道已经构建了什么。