I have a Makefile rule that requires storing the results from shell commands into variables for later use. For some reason, it seems that the $(shell)
call executes as soon as my rule is match, as opposed to when it is encountered during execution.
The file is as follows:
TMPDEV=/tmp/disk.img
$(TMPDEV):
fallocate -l 806354944 $(TMPDEV)
sudo parted --script $(TMPDEV) unit s mklabel msdos \
mkpart primary fat16 2048 526335 \
mkpart primary fat32 526336 1050623 \
mkpart primary NTFS 1050624 1574911 \
quit
$(eval TMPDISK := $(shell sudo partx --verbose -a $(TMPDEV) | tail -1 | cut -d':' -f1))
echo $(TMPDISK)
sudo mkfs.fat -F 16 -n FAT16 $(TMPDISK)p1
It is impossible to know what the value of TMPDISK
will be until at least after the fallocate
call; that is why the $(eval)
statement is delayed until after the disk image is partitioned.
The output I receive is:
$ make
partx: stat failed /tmp/disk.img: No such file or directory
fallocate -l 806354944 /tmp/disk.img || dd if=/dev/zero of=/tmp/disk.img bs=1b count=1574912
sudo parted --script /tmp/disk.img unit s mklabel msdos \
mkpart primary fat16 2048 526335 \
mkpart primary fat32 526336 1050623 \
mkpart primary NTFS 1050624 1574911 \
quit
echo
The fact that partx
errors out (and thus TMPDISK
is set to empty) before any of the other commands execute makes me think that $(shell)
is called earlier than intended. Is there anyway to delay the shell call and the assignment to TMPDISK
until the appropriate line?
= defines a recursively-expanded variable. := defines a simply-expanded variable.
There is one way that the makefile can change a variable that you have overridden. This is to use the override directive, which is a line that looks like this: ' override variable = value ' (see The override Directive).
The eval function is very special: it allows you to define new makefile constructs that are not constant; which are the result of evaluating other variables and functions. The argument to the eval function is expanded, then the results of that expansion are parsed as makefile syntax.
It is not possible to delay expansion like this. Make always expands all the variables in the entire recipe first, before it sends any part of the recipe to the shell. There is no way to "defer" that until later.
Generally, it's not typical to use $(shell ...)
in a recipe, since the recipe is already running in a shell. And setting make variables inside a recipe via $(eval ...)
is also highly unusual.
I would recommend that you rewrite this recipe to use shell variables, not make variables; it will be much more understandable:
TMPDEV=/tmp/disk.img
$(TMPDEV):
fallocate -l 806354944 $(TMPDEV)
sudo parted --script $(TMPDEV) unit s mklabel msdos \
mkpart primary fat16 2048 526335 \
mkpart primary fat32 526336 1050623 \
mkpart primary NTFS 1050624 1574911 \
quit
TMPDISK=$$(sudo partx --verbose -a $(TMPDEV) | tail -1 | cut -d':' -f1); \
echo $$TMPDISK; \
sudo mkfs.fat -F 16 -n FAT16 $${TMPDISK}p1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With