I'm experiencing behavior where a gmake $(shell) construct that works in my local environment fails under certain conditions when running within Travis CI invoked from github. When invoking the gmake construct
$(shell echo '{gen}' | sed -e "s#{gen}#$(GEN)#")
as part of a make action, it works fine both in my local Debian environment and inside CI. But when invoking it to set a Makefile variable:
SPECSRC = $(shell echo '{gen}' | sed -e "s#{gen}#$(GEN)#")
it still works locally, but fails when executed under Travis with the error message:
mf.test:11: *** unterminated call to function 'shell': missing ')'. Stop.
I've checked some obvious things - both are running /bin/bash in their respective environments, and there are very close (not identical) gmake / sed / bash versions in the two environments. Alternate sed-expression separators like '@' instead of '#' (see mf.test below) do not help.
If this were something happening in .travis.yml I'd think about metacharacters, but this is only invoked under Travis - the offending commands are executing entirely inside gmake through the $(shell) construct. Any thoughts on why this is happening, and how I could avoid it?
Trivial makefile 'mf.test' follows:
# Very stripped-down test Makefile
GEN = $(CURDIR)/gen
all: shell shellvar
shell:
echo 'shell: trying inline shell-sed'
echo $(shell echo '{gen}' | sed -e "s#{gen}#$(GEN)#")
SPECSRC = $(shell echo '{gen}' | sed -e "s#{gen}#$(GEN)#")
shellvar:
echo 'shellvar: trying shell-sed through a variable'
echo SPECSRC = $(SPECSRC)
I expected:
make -f mf.test
to result in something like (depending on path):
echo 'shell: trying inline shell-sed'
shell: trying inline shell-sed
echo /home/tree/git/opencl/github-Docs/gen
/home/tree/git/opencl/github-Docs/gen
echo 'shellvar: trying shell-sed through a variable'
shellvar: trying shell-sed through a variable
echo SPECSRC = /home/tree/git/opencl/github-Docs/gen
SPECSRC = /home/tree/git/opencl/github-Docs/gen
Run locally, this happens. Running under Travis CI (see link in my comment), I get
echo 'shell: trying inline shell-sed'
shell: trying inline shell-sed
echo /home/travis/build/KhronosGroup/OpenCL-Docs/gen
/home/travis/build/KhronosGroup/OpenCL-Docs/gen
mf.test:11: *** unterminated call to function 'shell': missing ')'. Stop.
It's because there's a different version of GNU Make running on Travis. The formulation you have is not portable between different versions of GNU Make because the comment character #
was not properly ignored inside variable/function references in some older versions of GNU Make.
If you want your makefile to be portable you have to "hide" the comment character in a variable, like this:
HASH := \#
SPECSRC = $(shell echo '{gen}' | sed -e "s$(HASH){gen}$(HASH)$(GEN)$(HASH)")
Note, it's (virtually) always a bad idea to use recursive assignment =
with $(shell ...)
. Unless you have very unusual requirements you should always use simple assignment :=
. This is not related to your problem however.