今天折腾了好久,就为了debug两个makefile的bug。虽然最后找到原因了,但是,怎么说呢,用现在流行的话来说,实在是意难平啊!必须写一篇记录一下!
第一个问题,是个语法高亮问题。今天观察到makefile里一些有缩进的语句,没有被正确的语法高亮,比如下面这样:
而正常来说,B应该被识别成变量:
问题的原因是在写非recipe的时候,缩进应该使用空格而非TAB。在写makefile中的recipe时,因为实际上我们写的是希望shell执行的语句,所以使用的是shell syntax。而make识别recipe的方式就是缩进使用TAB。而其他时候,比如上面的例子中,我们并非在写recipe,这时候syntax应该按照makefile风格来写,所以应当使用空格来缩进。这也正是编辑器对语法高亮识别的方式。
虽然看起来只是语法高亮的问题,但归根结底是make如何识别makefile中语句的问题。错误的缩进可能导致其他问题,比如在下面的例子中:
A
我们的本意是打印B的值,但是执行结果却是打印了一个空行,同时接着一行B=B。这背后的原因,就是B=B这一行使用了TAB来缩进,因此make把这一行也当做recipe的一部分,于是将其交给Shell执行。而除此之外,makefile中没有定义B的值,因此echo打印了一个空行,并且B=B也被打印出来。
可以参考GNU Make 5.1节深入学习recipe syntax问题。
第二个问题看起来就更奇怪一些。出错的代码类似下面这样:
A
看起来打印的结果应该是B,但实际上执行的结果却打印了C:
这个问题表面上看非常不可思议。而真正发现问题之后,也让人不禁摇头感叹。这个问题其实上仅仅因为A=A这一行的结尾多了一个空格。所以变量A实际上值是"A "。故而ifeq语句走了else分支。
这种问题知道之后觉得是个非常郁闷,但makefile似乎很难避免这样的问题。因为在makefile中,语句之间没有分隔符号,同时对字符串变量也不需要加引号。在我们日常使用的很多语言中,空格是可以自由添加的,本身不代表任何含义。所以习惯了其他语言语法的我们,面对这种"ghost white space"真的很难发现。我们只能要求维护makefile的同事多留心了。
另外,对于变量来说,实际上=前后是允许有空格的,并且会被忽略掉,不会当做值的一部分。但行尾的空格则相反。
希望以后都不要再debug makefile问题了……愿这篇文章没有更新……