views:

459

answers:

3

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.

+2  A: 

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
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
@Josh Kelley: .PHONY will take care of that.
derobert
You're right, sorry.
Josh Kelley
+3  A: 

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

toplevel:
    -mkdir $(TEMPDIR)
    $(MAKE) $(MLAGS) all
    -rm -rf $(TEMPDIR)

all: ... rest of stuff.

I've done similar tricks for making in subdirectories:

all:
    @for i in $(SUBDIRS); do \
        echo "make all in $$i..."; \
        (cd $$i; $(MAKE) $(MLAGS) 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
paxdiablo
That works, but of course only if the user says 'make' without specifying a target. So 'make all' won't work etc.
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
Updated so that you can "make all" which is also the default rule.
paxdiablo
A: 

make doesn't support this directly, and trying to do it manually from the makefile is just too difficult, since you need to delete the directory regardless of which rule is run, even if a rule fails, and even if no rules are invoked (because the target is up to date).

The best solution that I've found is to wrap the Makefile in a shell script make.sh:

#!/bin/bash

TEMPDIR=$(mktemp -d -t) || exit 1
export TEMPDIR

trap "rm -rf $TEMPDIR" 0

make $@

Then, in your Makefile, add a rule to verify that TEMPDIR was set:

ifeq ($(TEMPDIR),)
$(error TEMPDIR environment variable not defined (try running from make.sh))
endif

Then just run make.sh instead of make.

Josh Kelley