I am puzzled by the difference between the "shell" MAKE function and "$$". In the documentation I find:
The shell function accepts a single argument that is expanded (like all arguments) and passed to a subshell for execution. The standard output of the command is then read and returned as the value of the function.
I believed this was exactly what "$$" was doing as well, however in this small example:
a = $(shell find . -maxdepth 1 -type f -name "Makefile")
b = $$(find . -maxdepth 1 -type f -name "Makefile")
.PHONY: all A B
all: A B
A: $(a)
@echo "Target: $(@)"
@echo "Prereq: $(<)"
@echo "Var a: $(a)"
@echo "Var b: $(b)"
B: $(b)
@echo "Target: $(@)"
@echo "Prereq: $(<)"
@echo "Var a: $(a)"
@echo "Var b: $(b)"
the output is the following:
Target: A
Prereq: Makefile
Var a: ./Makefile
Var b: ./Makefile
make: *** No rule to make target '$(find)', needed by 'B'. Stop.
Note here that it says "No rule to make target '$(find)'", as if the argument has not yet been expanded. (I also tried to make the variable simply expanded, "b:=$$(...)", but this changed nothing).
I hope that someone has the knowledge to elaborate more on this, which to me seems like a subtle difference, but probably is much more profound than I can comprehend at this time.
$(shell ...) is a Make text function. Make will expand this, so in your example, a will expand, when substituted, to the result of the find command. (If you made it a simply-expanded variable, the shell command would be evaluated only once, of course).
$$ is just expanded to $, so in your example, b will substitute as the value $(find . -maxdepth 1 -type f -name "Makefile"). This will be the same whether b is defined with = or :=.
When you use $(b) in a command such as echo $(b), the shell running that command will see this as command substitution. In other words, you have echo $(find ...) as a shell command.
Using $(b) in a Make target or dependency will, as you have seen, perform no further evaluation.
Here's another example Makefile, which I hope demonstrates what's going on. We use single-quotes to show literally what the shell is given:
a = $$(echo true)
b = $(shell echo true)
print:
echo '$$a: $a' = "$a"
echo '$$b: $b' = "$b"
.PHONY: print
This gives me
echo '$a: $(echo true)' = "$(echo true)"
$a: $(echo true) = true
echo '$b: true' = "true"
$b: true = true
showing that in the first case, the shell is given $(echo true) in its command, whereas in the second case, Make evaluates echo true and simply substitutes the result true into the command.
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