如何在Makefile中自动创建(和删除)临时目录?

21

在执行第一个目标之前,让make创建一个临时目录是否可能?也许可以使用一些技巧、额外的目标等等来实现?

Makefile 中的所有命令都可以将自动创建的目录称为$TMPDIR,当make命令结束时,该目录会被自动删除。

4个回答

26

之前的答案要么无法正常工作,要么过于复杂。下面是我找到的一个更为简单明了的示例:

PACKAGE := "audit"
all:
    $(eval TMP := $(shell mktemp -d))
    @mkdir $(TMP)/$(PACKAGE)
    rm -rf $(TMP)

2
在GNU make中运行得非常好。但在BSD make中不行。 - Dereckson
5
如果有任何错误,它不会进行清理,这也是它的一个特点 :) - stefanct

23

至少在GNU make中,

TMPDIR := $(shell mktemp -d)

使用sys_get_temp_dir()函数可以获取临时目录。我想不到一个好的方法来在结束时清理它,除了在all目标的一部分中明显地加入rmdir "$(TMPDIR)"


如果所有目标都是最新的,那么评估 TMPDIR 将创建该目录,并且 all 的规则将永远不会执行删除它的操作。 - Josh Kelley
1
@Josh Kelley:.PHONY会处理这个问题。 - derobert
这会在每次执行任何配方时创建一个临时文件,对吗?.PHONY目标如何处理删除TMPDIR - Ari Sweedler
1
@AriSweedler 那是假设 all 是唯一的目标,我想。或者只有几个目标,所以你可以从每个目标中删除。 - derobert
提供 mktemp -p myprefix -drm -rf myprefix* - IljaBek
1
注意:每次使用“variable”时,这将创建一个新的临时目录!必须使用TMPDIR:= $(realpath $(shell mktemp -d)) - MKesper

11

请参考如何从Makefile获取其文件名,其中介绍了$(self)技巧。

ifeq ($(tmpdir),)

location = $(CURDIR)/$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
self := $(location)

%:
    @tmpdir=`mktemp --tmpdir -d`; \
    trap 'rm -rf "$$tmpdir"' EXIT; \
    $(MAKE) -f $(self) --no-print-directory tmpdir=$$tmpdir $@

else
# [your real Makefile]
%:
    @echo Running target $@ with $(tmpdir)
endif

9

我记得能够递归调用make,大概是这样的:

all:
    -mkdir $(TEMPDIR)
    $(MAKE) $(MFLAGS) old_all
    -rm -rf $(TEMPDIR)

old_all: ... rest of stuff.

我曾经为在子目录中调用make做过类似的技巧:

all:
    @for i in $(SUBDIRS); do \
        echo "make all in $$i..."; \
        (cd $$i; $(MAKE) $(MFLAGS) all); \
    done

刚刚验证过,这个方法可行:

$ cat Makefile
all:
    -mkdir tempdir
    -echo hello >tempdir/hello
    -echo goodbye >tempdir/goodbye
    $(MAKE) $(MFLAGS) old_all
    -rm -rf tempdir

old_all:
    ls -al tempdir

$ make all
mkdir tempdir
echo hello >tempdir/hello
echo goodbye >tempdir/goodbye
make  old_all
make[1]: Entering directory '/home/pax'
ls -al tempdir
total 2
drwxr-xr-x+ 2 allachan None 0 Feb 26 15:00 .
drwxrwxrwx+ 4 allachan None 0 Feb 26 15:00 ..
-rw-r--r--  1 allachan None 8 Feb 26 15:00 goodbye
-rw-r--r--  1 allachan None 6 Feb 26 15:00 hello
make[1]: Leaving directory '/home/pax'
rm -rf tempdir

$ ls -al tempdir
ls: cannot access tempdir: No such file or directory

那个可以运行,但是只有当用户没有指定目标时才有效。所以 'make all' 等等不会起作用。 - Frank
我期望用户知道他们在做什么 :-) 所以他们会使用“make”或“make toplevel”。无论如何,如果您想要那种行为,您可以将“all”更改为“old_all”,将“toplevel”更改为“all”。 - paxdiablo
更新了"make all"规则,该规则也是默认规则。 - paxdiablo
在mkdir等命令前面的破折号是用来做什么的? - nnnmmm
1
@nnnmmm,它们告诉make忽略命令的返回代码。否则,失败会导致make停止。 - paxdiablo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接