美文网首页程序员
Makefile:一个空格引发的惨案

Makefile:一个空格引发的惨案

作者: Mum_Chen | 来源:发表于2019-10-17 15:15 被阅读0次

从一个bug说起

最早发现makefile关于空格的"特性"是源于一个bug. 在某个项目中, 我需要大量拷贝相同的变量, 所以实现了一个clone的方法, 用于实现把src_xxx的值拷贝到dest_xxx.

我仿照当时的情况写了一个精简的版本. 代码如下:

# makefile
src_int = 10
src_char = "char"

# clone attributes from src to dest.
# arg1: destTarget
# arg2: srcTarget
# arg3: attr_list
define Clone
$(foreach att,$(3), $(eval $(1)_$(att) := $($(2)_$(att))))
endef

$(call Clone,targetA,src,int char)
$(call Clone, targetB, src, int char)
all: targetA targetB

targetA:
    @echo "targetA: int=$(targetA_int) char=$(targetA_char)"

targetB:
    @echo "targetB: int=$(targetB_int) char=$(targetB_char)"

运行后的结果如下:

$ make all
targetA: int=10 char=char
targetB: int= char=

从结果看到targetA克隆成功了, 但是targetB没有.

为什么会发生这个

其实问题的根源就在于脚本中的这两行:

$(call Clone,targetA,src,int char)
$(call Clone, targetB, src, int char)

targetB的克隆比targetA多了几个空格. Makefile的字符串替换包括空格.
在Clone函数中的$(eval $(1)_$(att) := $($(2)_$(att))))这一段代码里的
$($(2)_$(att)))在两种情况下被解析成为了不同变量.

对于targetA而言: $($(2)_$(att)))被解析为了$(src_$(att)).
对于targetB而言: $($(2)_$(att)))被解析为了$( src_$(att)).

后者比前者多了一个空格, 在makefile的上下文中找不到对应的变量, 所以赋值失败.

当时, 由于习惯使然, 我在逗号后面随手加入了一个空格. 然后我就发现我的构建脚本不能正常运行了.

如何解决

解决方案1: 改变逗号后面加空格的习惯.

然而这种方案过于反人类, 所以我放弃了.(但是修改起来比较快)
考虑到我就是一个写bug的, 不能这么严格的要求自己, 所以我找到了方案2.

解决方案2: 使用strip函数进行变量的处理.

修改如下:

define Clone
$(foreach att,$(3), $(eval $(1)_$(att) := $($(2)_$(att))))
endef

define CloneFix
$(foreach att,$(3), $(eval $(strip $(1))_$(att) := $($(strip $(2))_$(att))))
endef

附录

完整的代码

src_int = 10
src_char = "char"

# arg1: destTarget
# arg2: srcTarget
# arg3: value_list
define Clone
$(foreach att,$(3), $(eval $(1)_$(att) := $($(2)_$(att))))
endef

define CloneFix
$(foreach att,$(3), $(eval $(strip $(1))_$(att) := $($(strip $(2))_$(att))))
endef

%_print:
    @echo "$*: int=$($*_int) char=$($*_char)"

gap:
    @echo

# arg1: target list
define Entry
$(foreach target,$(1), $(eval $(target): $(target)_print))
endef

$(call Entry, v1_a v1_b v1_c v1_d)
$(call Clone,v1_a,src,int char)     # with not space
$(call Clone,v1_b,src, int char)    # space in arg3(param)
$(call Clone,v1_c, src, int char)   # space in arg2(src)
$(call Clone, v1_d,src, int char)   # space in arg1(dest)

$(call Entry, v2_a v2_b v2_c v2_d)
$(call CloneFix,v2_a,src,int char)      # with not space
$(call CloneFix,v2_b,src, int char) # space in arg3(param)
$(call CloneFix,v2_c, src, int char)    # space in arg2(src)
$(call CloneFix, v2_d,src, int char)    # space in arg1(dest)

.DEFAULT_GOAL := all
all: v1 gap v2
v1: $(addprefix v1_, a b c d)
v2: $(addprefix v2_, a b c d)

运行结果

$ make
v1_a: int=10 char=char
v1_b: int=10 char=char
v1_c: int= char=
v1_d: int=10 char=char

v2_a: int=10 char=char
v2_b: int=10 char=char
v2_c: int=10 char=char
v2_d: int=10 char=char

这个版本不管怎么按空格Clone函数都能被正常的执行.

相关文章

  • Makefile:一个空格引发的惨案

    从一个bug说起 最早发现makefile关于空格的"特性"是源于一个bug. 在某个项目中, 我需要大量拷贝相同...

  • 一辆东方罗密欧引发的惨案

    一辆东方罗密欧引发的惨案 一辆东方罗密欧引发的惨案ufo大大雄 2017.1.21 这是一个很有趣的故事,也算是一...

  • 惨!因为朋友圈的信息他丢了工作,我们该如何避免这样的职场惨剧

    01 因为社交媒体引发的“职场惨案” 这段时间,社交媒体俨然成了引发“职场惨案”的高危地带,不断有人因为在微博或朋...

  • UIWindow引发的惨案

    本篇博文纯粹是UIWindow引发的一场血案. 起因是在swift项目里添加一个广告页时,思路是创建一个UIVie...

  • 聚会引发的惨案

    我的生活正默默地朝着某一个方向转变,虽然我不知道这转变是好是坏,只能说变幻莫测又不可预知的这不正是人生? 怎么也...

  • ^M引发的惨案

    放假前写了一个脚本用来提取基因名对应的序列,放假后再用这个脚本居然就不好使了!!! 针对单个变量检查命令后发现:同...

  • 一个电话引发的惨案

    李玉换了个新手机,从旧手机把手机卡换过来后发现,通讯录只剩一个人了!本来她存的联系人就不多,现在又都是微信...

  • 一个快递引发的惨案

    今天我跟我儿子一起去拿快递,拆开快递之后,儿子就说快递是他的,我说这是别人寄给妈妈的,儿子非不行。 他爸也来帮忙分...

  • 一个口罩引发的惨案

    众所周知,今年的疫情,我们在家呆了27天,豪无准备的留在家里,为祖国做贡献。每天刷着疫情,看着朋友圈。家里有...

  • 一个术语引发的惨案

    这周,金融市场风起云涌,也出现了一些有意思的乌龙。 周一国际原油价格暴跌,各平台纷纷呼吁大家买入原油基金抄底。 买...

网友评论

    本文标题:Makefile:一个空格引发的惨案

    本文链接:https://www.haomeiwen.com/subject/ewlumctx.html