我遇到的行为是,在从 github 调用的 Travis CI 中运行时,在本地环境中工作的 gmake $(shell) 构造在某些条件下失败。调用 gmake 构造时
$(shell echo '{gen}' | sed -e "s#{gen}#$(GEN)#")
作为 make操作的一部分,它在我的本地 Debian 环境和 CI 内部都运行良好。但是当调用它来设置 Makefile变量时:
SPECSRC = $(shell echo '{gen}' | sed -e "s#{gen}#$(GEN)#")
它仍然可以在本地工作,但在 Travis 下执行时失败并显示错误消息:
mf.test:11: *** 对函数“shell”的未终止调用:缺少“)”。停止。
我检查了一些明显的事情 - 两者都在各自的环境中运行 /bin/bash,并且这两个环境中的 gmake / sed / bash 版本非常接近(不相同)。备用 sed 表达式分隔符如“@”而不是“#”(请参阅下面的 mf.test)没有帮助。
如果这是在 .travis.yml 中发生的事情,我会考虑元字符,但这仅在 Travis 下调用- 违规命令完全通过 $(shell) 构造在 gmake 内部执行。关于为什么会发生这种情况以及如何避免这种情况有什么想法吗?
简单的 makefile 'mf.test' 如下:
# 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)
我期望:
make -f mf.test
导致类似的结果(取决于路径):
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
在本地运行,就会发生这种情况。在 Travis CI 下运行(请参阅我的评论中的链接),我得到
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.
这是因为 Travis 上运行着不同版本的 GNU Make。您所拥有的公式在不同版本的 GNU Make 之间不可移植,因为
#
在某些旧版本的 GNU Make 中,变量/函数引用内的注释字符没有被正确忽略。如果你希望你的 makefile 是可移植的,你必须“隐藏”变量中的注释字符,如下所示:
请注意,使用递归赋值(实际上)总是一个坏主意。除非您有非常不寻常的要求,否则您应该始终使用简单分配。但这与您的问题无关。
=
$(shell ...)
:=