在我的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脚本中,但这似乎有点不美观。


当前回答

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

其他回答

在您的示例中,每当计算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的变量。希望这足以防止冲突。

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

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

我在这里整合了一些相关技巧:makefile中的多行bash命令

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

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

在本例中,只要变量是单个目标的局部变量,就遵循@nobar的答案并使其成为shell变量。

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

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