Consider that a piece of GNU Makefile is generated by a command (probably because the list of variables to define is too complicated to achieve otherwise).
Script test.sh
:
echo 'V1 = foo bar'
echo 'V2 = ab cd'
If I try this in the GNU Makefile:
$(eval $(shell ./test.sh))
$(info V1='$(V1)')
$(info V2='$(V2)')
I get this:
V1='foo bar V2 = ab cd'
V2=''
while I would like this:
V1='foo bar'
V2='ab cd'
I understand that $(shell)
transforms new lines in spaces. I found similar, although not identical, questions online but answers were incorrect. For instance, using an explicit NL
variable in the Makefile:
define NL
endef
$(eval $(shell ./test.sh))
$(info V1='$(V1)')
$(info V2='$(V2)')
and then creating a reference to $(NL)
in the script:
echo 'V1 = foo bar$(NL)'
echo 'V2 = ab cd$(NL)'
I get this:
V1='foo bar
V2 = ab cd
'
V2=''
The reference to $(NL)
is replaced by one newline but that newline is swallowed into V1
instead of separating the definitions of variables.
I haven't found a way to use include
directive from a command output (apart from creating a temporary file, which is quite ugly in terms of cleanup).
This is an addendum to Thierry's self-answer to show how the ugliness can be isolated in a single function, which I'll call shell-lines
, with no need to modify the shell script. We can pipe the script's output through sed
to replace newline with a marker of our choice and subst
it back to newline:
define NL
endef
EOL = --EOL--
shell-lines = $(subst $(EOL),$(NL),$(shell ( $1 ) | sed 's/$$/$(EOL)/'))
Then we simply call this function - here, I'll inline a couple of commands rather than execute an external script:
$(eval $(call shell-lines, echo 'V1 = foo bar'; echo 'V2 = ab cd'))
Some notes:
sed
even if we supply multiple commands connected with ;
, ||
or &&
.$$
for sed to see $
matching end of line.EOL
between invocations - it should be something guaranteed not to occur naturally in output.Full makefile (for testing):
define NL
endef
EOL = --EOL--
shell-lines = $(subst $(EOL),$(NL),$(shell ( $1 ) | sed 's/$$/$(EOL)/'))
$(eval $(call shell-lines, printf '%s = %s\n' V1 'foo bar' V2 'ab cd'))
$(info V1='$(V1)')
$(info V2='$(V2)')
all:
@: