Running in Travis CI, weird behavior of $(shell) in a Makefile?

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:

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.

The issue arises from differing versions of GNU Make on Travis. Your makefile syntax isn’t universally compatible across GNU Make versions, specifically due to the handling of the comment character # in variable/function references in some older GNU Make versions.

To ensure portability in your makefile, encapsulate the comment character # within a variable like so:

HASH := \#
SPECSRC := $(shell echo '{gen}' | sed -e "s$(HASH){gen}$(HASH)$(GEN)$(HASH)")

Additionally, it’s generally inadvisable to use recursive assignment = with $(shell ...). In most cases, you should opt for simple assignment := instead. This recommendation, however, is not directly related to the issue you’re facing.

So to add additional files into the RPM package, I have added a custom install_script in the RPM spec file. This script copies files from the build directory into RPM_BUILD_ROOT. For example:

cp %{buildroot}/path/to/file1 $RPM_BUILD_ROOT/
cp {buildroot}/path/to/file2 $RPM_BUILD_ROOT/

Alternatively, I could have ran ‘make install’ directly in the %install section, or use the %make_install macro. Still no luck.

You could use xargs with I and a place-holder {} to store the value stdin and pass it over to sed as:

date +%s | md5sum | cut -d' ' -f 1 | xargs -I {} sed -i.bak 's/^\(CSS=\).*/CSS={}/' file

Although I would wisely avoid introducing another pipe-line and would use a separated command for sed:

newHash=$(date +%s | md5sum | cut -d' ' -f 1); sed -i.bak "s/^\(CSS=\).*/CSS=${newHash}/" file
1 Like

used your workaround (the example using sed, and args) it’s kind of a weird one but it worked. thanks @montana

Great to hear I was able to solve your issue.