This is a Makefile piece of code of how someone may use mktemp in a Makefile
TEST=$(shell mktemp -d)
mktemp:
echo $(TEST)
touch $(TEST)/test.txt
ls $(TEST)
cat $(TEST)/test.txt
rm -rf $(TEST)
This is an example output
❯ make mktemp
echo /var/folders/62/wkysd_4n0w57ljl9ycfsd9cc0000gn/T/tmp.tQI5EeyW
/var/folders/62/wkysd_4n0w57ljl9ycfsd9cc0000gn/T/tmp.tQI5EeyW
touch /var/folders/62/wkysd_4n0w57ljl9ycfsd9cc0000gn/T/tmp.lVL3N8Rp/test.txt
ls /var/folders/62/wkysd_4n0w57ljl9ycfsd9cc0000gn/T/tmp.sBW9FzgD
cat /var/folders/62/wkysd_4n0w57ljl9ycfsd9cc0000gn/T/tmp.Ti53SWSw/test.txt
cat: /var/folders/62/wkysd_4n0w57ljl9ycfsd9cc0000gn/T/tmp.Ti53SWSw/test.txt: No such file or directory
make: *** [mktemp] Error 1
The expectation is that cat /var/folders/62/wkysd_4n0w57ljl9ycfsd9cc0000gn/T/tmp.Ti53SWSw/test.txt
would not error.
How can mktemp be used in this case?
This line:
TEST=$(shell mktemp -d)
sets the value of the TEST
variable to the string $(shell mktemp -d)
. It doesn't expand that string (doesn't run the shell command), it just keeps the string as-is.
Now, every time you use that value later in the makefile, it's expanded which means mktemp
is run again, and you get a different value:
mktemp:
echo $(TEST)
touch $(TEST)/test.txt
ls $(TEST)
cat $(TEST)/test.txt
rm -rf $(TEST)
You want to use immediate expansion when you assign the variable, so that it is expanded only one time when the makefile is parsed; use:
TEST := $(shell mktemp -d)
Alternatively you can just write the recipe using shell operations and not use any make functions like shell
:
mktemp:
TEST=$$(mktemp -d) && \
echo $$TEST && \
touch $$TEST/test.txt && \
ls $$TEST && \
cat $$TEST/test.txt && \
rm -rf $$TEST
Note by default each logical line of a recipe is run in a separate shell, so in order to have all the lines run in the same shell (so they have access to the same $TEST
variable) you need to use backslash to combine them into a single logical line.