细数makefile遇到的那些坑
1号坑:
不好意思放错了,再来!!
示例1:
.PHONY: all
A=hello
ifeq($(A), hello)
INFO=true
else
INFO=false
endif
all:
@echo "result: $(INFO)"
执行结果:
$ make
Makefile:5: *** 缺失分隔符。 停止。
错误原因:
第5行:ifeq
和 (
之间应该有空格
2号坑:
示例2:
.PHONY: all
ifeq ($(A), hello)
INFO=true
else
INFO=false
endif
all:
@echo "result: $(INFO)"
执行结果:
$ make A=hello
result:
可以看到,INFO
未能赋值成功。并且示例中 INFO
赋值语句中 INFO
变量没有语法高亮。
错误原因:
INFO
赋值的两条语句前面应该使用空格,而不是tab键。
在写非recipe的时候,缩进应该使用空格而非TAB。在写makefile中的recipe时,因为实际上我们写的是希望shell执行的语句,所以使用的是shell syntax。而make识别recipe的方式就是缩进使用TAB。而其他时候,比如上面的例子中,我们并非在写recipe,这时候syntax应该按照makefile风格来写,所以应当使用空格来缩进。
总结:
经过测试发现,按照示例1中方式,将 A=hello
放在Makefile中,即使 INFO
赋值的两条语句前面使用tab键,执行 make
命令发现还是可以正确输出 result: true
的。比较奇怪。不过遇到这种情况,还是使用空格吧。
3号坑
示例3:
.PHONY: all
A=hello
ifeq ($(A), "hello")
INFO=true
else
INFO=false
endif
all:
@echo "result: $(INFO)"
执行结果:
$ make
result: false
错误原因:
语句 ifeq ($(A), "hello")
中第2个参数 "hello"
不能使用双引号。或者,变量 A
赋值语句应该为:A="hello"
。根本原因在于,比较时 "hello"
才是真正的字符串,而不是 hello
。
4号坑
示例4:
.PHONY: all
A=hello
ifeq ($(A), hello)
INFO=true
else
INFO=false
endif
all:
@echo "result: $(INFO)"
执行结果:
$ make
result: false
错误原因:
语句A=hello
后面多了一个空格。错误根因与示例3一致,该语句导致变量 A
的实际值是 hello
,而不是 hello
5号坑
示例5:
.PHONY: all
ifeq ($(A), "hello")
INFO=true
else
INFO=false
endif
all:
@echo "result: $(INFO)"
执行结果:
$ make A="hello"
result: false
$
$ make A=hello
result: false
错误原因:
语句 ifeq ($(A), "hello")
应该修改为 ifeq ($(A), hello)
。
我猜测,是因为执行语句 make A="hello"
和 make A=hello
都是在shell环境下。shell环境下赋值语句 A="hello"
和 A=hello
是等价的,实际 A
的值都是 hello
6号坑
示例6:
.PHONY: all
A=hello
ifeq ($(A), hello)
echo "A = hello"
else
echo "A != hello"
endif
all:
@echo "result: $(INFO)"
执行结果:
$ make
Makefile:6: *** 配方在第一个目标前开始。 停止。
错误原因:
我描述不太好,大概意思是 echo
是shell语句,只能在目标中使用。下面是正确写法:
正确写法:
示例6-2:
.PHONY: all
A=hello
all:
@echo "result: $(INFO)"
ifeq ($(A), hello)
echo "A = hello"
else
echo "A != hello"
endif
正确写法执行结果:
$ make
result:
echo "A = hello"
A = hello
7号坑
示例7:
.PHONY: all
A=hello
ifeq ($(A), hello)
echo "A = hello"
else
echo "A != hello"
endif
all:
@echo "result: $(INFO)"
执行结果:
$ make
Makefile:6: *** 缺失分隔符。 停止。
乍一看,示例6 和 示例7 代码代码是一样的,为什么报错不一样。
实际上,示例6 条件分支中的两个 echo
语句前面是tab键;示例7 条件分支中的两个 echo
语句前面是空格
8号坑
示例8:
.PHONY: all
A=hello
all:
@echo "result: $(INFO)"
ifeq ($(A), hello)
echo "A = hello"
else
echo "A != hello"
endif
执行结果:
$ make
Makefile:9: *** 缺失分隔符。 停止。
错误原因:
示例8 代码和 6号坑 中的正确写法示例6-2非常像,区别在于示例8 中最后两个echo
语句前面是空格,而示例6-2最后两个echo
语句前面是tab键。根因: echo
是shell语句,需要在目标中才能使用,并且makefile的目标中使用shell语句,需要在语句前使用tab缩进。
9号坑
示例9:
.PHONY: all
A=hello
all:
@echo "result: $(INFO)"
ifeq ($(A), hello)
echo "A = hello"
else
echo "A != hello"
endif
执行结果:
$ make
result:
ifeq (hello, hello)
/bin/sh: -c: 行 0: 未预期的符号“hello,”附近有语法错误
/bin/sh: -c: 行 0: `ifeq (hello, hello)'
make: *** [Makefile:7:all] 错误 1
错误原因:
ifeq
、 else
、 endif
前面使用了tab缩进。
makefile的目标中,使用tab缩进来表示该条语句是shell语句。然而,ifeq
、 else
、 endif
是makefile的条件判断语法,不是shell语句,因此不能在ifeq
、 else
、 endif
前面使用tab缩进,可是使用空格缩进,或者按照6号坑 中的正确写法示例6-2写法,不进行缩进。