Reputation: 7799
In my Makefile I want to execute multiple steps as a part of a single target. Those steps should be done sequentially, because they depend on one another. This is the simplified case:
target:
git archive --remote=some-remote master --format zip -o ./zipfile.zip
echo "$(VARIABLE_IN_MAKE):$(shell unzip -z ./zipfilezip | tail -1)" > ./textfile
$(shell cat ./textfile)
The problem here is that the shell command - $(shell unzip -z ./zipfilezip | tail -1)
is executed as soon as the rule is "loaded", i.e. before the zipfile even exists. That returns errors. The cat
command is also expanded too early.
What is the correct way to execute a subshell not before, but only after all the steps above have finished? Do I have to wrap all the commands in a bash -c
call? Or chain them via &&
?
Upvotes: 1
Views: 545
Reputation: 29250
Get rid of these $(shell...)
. Each line of a make recipe is already a shell script:
target:
git archive --remote=some-remote master --format zip -o ./zipfile.zip
echo "$(VARIABLE_IN_MAKE):$$(unzip -z ./zipfilezip | tail -1)" > ./textfile
cat ./textfile
Note that, in the second line, $$(unzip -z ./zipfilezip | tail -1)
is expanded twice: a first time by make before passing the recipe to the shell, leading to $(unzip -z ./zipfilezip | tail -1)
, and a second time by the shell that treats it as a command substitution. This is why the $$
is needed: to escape the first expansion by make. If you were using $(unzip -z ./zipfilezip | tail -1)
directly, make would expand it as the empty string (unless you have a make variable which name is unzip -z ./zipfilezip | tail -1
, but this is very unlikely).
Upvotes: 3