Lam*_*eta 8 bash makefile gnu-make
我使用make的shell命令来填充一些变量,并在输出时指示它们被设置为我期望的值.然而,当我把它们传递给我的制作食谱时,它们都显示为空.我怀疑make正在对结果做一些奇怪的解析.例如:
MyTarget: $(MySources)
LINE='$(shell cat $< | grep GIMME_THE_LINE_I_WANT)'
CH9=$(shell echo $(LINE) | cut -b9)
echo $(CH9) # doesn't print anything
Run Code Online (Sandbox Code Playgroud)
我通过设置手动检查了我的生成器命令SHELL=sh -XV,当我运行相同的命令时,我得到正确的值,它看起来像bash是'归零'我的变量.知道什么是错的吗?
lar*_*sks 18
这里有几件事情.首先是当你有:
MyTarget: $(MySources)
LINE='$(shell cat $< | grep GIMME_THE_LINE_I_WANT)'
Run Code Online (Sandbox Code Playgroud)
您正在设置一个名为shell变量LINE,而不是make变量.目标的构建指令都是shell命令.所以在第一行之后,shell变量$LINE包含GIMME_THE_LINE_I_WANT.然而...
... 目标的构建指令中的每一行都在一个单独的shell进程中运行.所以如果你有:
mytarget:
MYVAR=foo
echo $$MYVAR
Run Code Online (Sandbox Code Playgroud)
您将看不到输出,因为$MYVAR未在第二个命令的上下文中设置.还要注意$$这里的使用,因为否则$会被Make解释(也就是说,写入$MYVAR实际上是make表达式$M后跟文本YVAR).您可以通过逻辑将您的行连接到单个shell脚本来解决此问题,如下所示:
mytarget:
MYVAR=foo; \
echo $$MYVAR
Run Code Online (Sandbox Code Playgroud)
的\是延伸在多个物理线路的单个逻辑线路生成文件的语法,当然;是在一行的多个命令组合简单地壳语法.
考虑到这一切,我们可以像这样重写您的目标:
MyTarget: $(MySources)
LINE=$$(cat $< | grep GIMME_THE_LINE_I_WANT); \
CH9=$$(echo $$LINE | cut -b9); \
echo $$CH9
Run Code Online (Sandbox Code Playgroud)
请注意,由于我们已经在运行shell脚本,所以我没有使用Make的$(shell ...)构造,并且我确保要转义所有$字符以确保shell而不是Make正在处理变量扩展.
更进一步,你不需要cat在那个脚本中使用; 你可以简单地写:
MyTarget: $(MySources)
LINE=$$(grep GIMME_THE_LINE_I_WANT $<); \
CH9=$$(echo $$LINE | cut -b9); \
echo $$CH9
Run Code Online (Sandbox Code Playgroud)
要么:
MyTarget: $(MySources)
CH9=$$(grep GIMME_THE_LINE_I_WANT $< | cut -b9); \
echo $$CH9
Run Code Online (Sandbox Code Playgroud)
(注意:虽然与此解决方案没有密切关系,但值得注意的是,每个调用$(shell ...)也在一个单独的进程中运行,因此一个变量集在另一个变量中不可用.)