21

Is it possible to have make create a temp directory before it executes the first target? Maybe using some hack, some additional target etc.?

All commands in the Makefile would be able to refer to the automatically created directory as $TMPDIR, and the directory would be automatically removed when the make command ends.

pinkgothic
  • 6,081
  • 3
  • 47
  • 72
Frank
  • 64,140
  • 93
  • 237
  • 324

4 Answers4

26

These previous answers either didn't work or seemed overly complicated. Here is a far more straight forward example I was able to figure out:

PACKAGE := "audit"
all:
    $(eval TMP := $(shell mktemp -d))
    @mkdir $(TMP)/$(PACKAGE)
    rm -rf $(TMP)
TaylorSanchez
  • 463
  • 1
  • 5
  • 8
23

With GNU make, at least,

TMPDIR := $(shell mktemp -d)

will get you your temporary directory. I can't come up with a good way to clean it up at the end, other than the obvious rmdir "$(TMPDIR)" as part of the all target.

derobert
  • 49,731
  • 15
  • 94
  • 124
  • If all targets are up to date, then evaluating `TMPDIR` will create the directory, and `all`'s rules will never be executed to delete it. – Josh Kelley Sep 27 '10 at 14:17
  • 1
    @Josh Kelley: .PHONY will take care of that. – derobert Sep 29 '10 at 05:07
  • This will create a temp file every time you execute *any* recipe, right? How will a `.PHONY` target take care of deleting `TMPDIR`? – Ari Sweedler May 15 '18 at 17:34
  • 1
    @AriSweedler that was assuming `all` was the only target, I think. Or that there are only a few targets, so you can remove from each. – derobert May 19 '18 at 05:10
  • provide `mktemp -p myprefix -d` and `rm -rf myprefix*` – IljaBek Jul 15 '20 at 20:29
  • Attention: this will create a new tempdir every time using the "variable"! Had to use TMPDIR := $(realpath $(shell mktemp -d)) – MKesper Oct 18 '22 at 08:33
11

See Getting the name of the makefile from the makefile for the $(self) trick

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
Community
  • 1
  • 1
Stefan
  • 5,304
  • 2
  • 25
  • 44
9

I seem to recall being able to call make recursively, something along the lines of:

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

old_all: ... rest of stuff.

I've done similar tricks for calling make in subdirectories:

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

Just checked it and this works fine:

$ 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
Jackenmen
  • 193
  • 1
  • 4
  • 11
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • That works, but of course only if the user says 'make' without specifying a target. So 'make all' won't work etc. – Frank Feb 26 '09 at 06:03
  • I expect the user to know what they're doing :-) so they would use "make" or "make toplevel". In any case, you can change "all" to "old_all" and "toplevel" to "all" if you want that behavior. – paxdiablo Feb 26 '09 at 06:05
  • Updated so that you can "make all" which is also the default rule. – paxdiablo Feb 26 '09 at 06:07
  • What are the dashes before mkdir etc. for? – nnnmmm Jun 12 '19 at 11:27
  • 1
    @nnnmmm, they tell `make` to ignore the return code of the command. Otherwise, a failure would cause `make` to stop. – paxdiablo Jun 12 '19 at 11:52