Your Makefile is a strange mix of shell and make constructs. If you are new to make you should probably use only shell constructs in recipes, plus maybe make variable expansions ($(VARIABLE)). But let's try to see what's going on when you run make with this.
First, it is important to understand that make expands the recipes before passing them to the shell. And when it expands your recipe it finds $(error ...). So it prints the error message and stops before the shell runs.
So, let's replace this $(error ...) with $(info error ...) to avoid that:
define print_error
final_error="$(error_prefix) $1 $2"
echo $(info error fe:$(final_error))
$(info error fe:$(final_error))
endef
Make parses your Makefile and discovers that it must run the recipes of phony target test. Before passing the recipes to the shell it expands them.
When make expands the 2 first lines of your recipes it just replaces the $$ with $. That's fine. When it expands the 2 last lines it first expands the parameter of value: $response. As you don't have a make variable named r, $r expands as the empty string and the parameter of value becomes esponse. As you don't have a make variable named esponse, $(value esponse) expands as the empty string. You could have written $(call print_info, , A), it would do the same (note the space between the two commas and before A).
When make expands $(call print_info, , A) it replaces it with (leading tabs and spaces not shown):
final_info="$(error_prefix) A"
echo $(info fi:$(final_error))
$(info fi:$(final_error)); \
Note: there are 3 spaces before A. Do you understand why?
The expansion continues recursively. Let's first expand the make variables error_prefix and final_error. As you don't have a make variable named final_error (you have a shell variable with this name but that's different from a make variable) it expands again as the empty string. This gives:
final_info="ERROR: A"
echo $(info fi:)
$(info fi:); \
The expansion of info prints the information message and expands as the empty string. So you see:
fi:
fi:
on the standard output and the recipe becomes:
final_info="ERROR: A"
echo
; \
That's the end of this expansion. The expansion of the last line similarly becomes:
final_error="ERROR: B"
echo
;
and two more lines are printed on the standard output which should now look like:
fi:
fi:
error fe:
error fe:
At this point your recipe is (again, leading tabs and spaces not shown):
response=$(eval curl -s -o /dev/null -w "%{http_code}" www.google.com); \
echo $response; \
final_info="ERROR: A"
echo
; \
final_error="ERROR: B"
echo
;
That's 5 different recipes:
Recipe 1:
response=$(eval curl -s -o /dev/null -w "%{http_code}" www.google.com); \
echo $response; \
final_info="ERROR: A"
Recipe 2:
echo
Recipe 3:
; \
final_error="ERROR: B"
Recipe 4:
echo
Recipe 5:
;
Make first echoes Recipe 1 and your standard output now looks like:
fi:
fi:
error fe:
error fe:
response=$(eval curl -s -o /dev/null -w "%{http_code}" www.google.com); \
echo $response; \
final_info="ERROR: A"
Then make passes Recipe 1 to the shell that runs eval curl ... (why eval?), stores the output 200 in shell variable response, echoes it, and stores ERROR: A in shell variable final_info. Your standard output is now:
fi:
fi:
error fe:
error fe:
response=$(eval curl -s -o /dev/null -w "%{http_code}" www.google.com); \
echo $response; \
final_info="ERROR: A"
200
Note that shell variables response and final_info are local to this recipe execution; make executes the different recipes in different shell processes. So after Recipe 1 has been executed the values of shell variables response and final_info is definitely lost. In case you expected them to be available when executing the next recipes, forget about it, they are gone.
Make then echoes Recipe 2 and passes it to the shell that simply adds a newline:
fi:
fi:
error fe:
error fe:
response=$(eval curl -s -o /dev/null -w "%{http_code}" www.google.com); \
echo $response; \
final_info="ERROR: A"
200
echo
It finally echoes Recipe 3:
fi:
fi:
error fe:
error fe:
response=$(eval curl -s -o /dev/null -w "%{http_code}" www.google.com); \
echo $response; \
final_info="ERROR: A"
200
echo
; \
final_error="ERROR: B"
When it passes Recipe 3 to the shell there is an error:
/bin/sh: -c: line 0: syntax error near unexpected token `;'
/bin/sh: -c: line 0: `; \'
make: *** [Makefile:19: test] Error 2
because you cannot have a semi-colon like this at the beginning of a list of shell commands. Make stops and Recipe 4 and Recipe 5 are not echoed or executed.
echo $(info...)does not really make sense. If you want to print something when the shell runs a recipe simplyecho something. And if you want to see it when make expands the recipe (before passing it to the shell), then simply$(info something). And why do youeval curl ...instead of justcurl?$(value $response)in a recipe is expanded by make.$responseprobably becomesesponsebecause you have no make variable namedr. And$(value esponse)probably becomes the empty string because you have no make variable namedesponse.makeis good at what it's intended for, but it is a darn poor choice of scripting language.