makefile中常见的一些问题和需要注意的地方

强制执行

每一条命令运行完,make会检查返回码,如果成功执行,会执行下一条命令,所有命令都正确执行,这个规则就算是执行成功。如果其中有一条命令执行失败,make就会终止当前规则,导致终止所有规则的执行。
个别时候,命令出错不一定是错的,比如mkdir,如果目录存在,那就不需要我们创建了,我们并不会觉得这是一个错误,我们希望程序继续执行。我们需要忽略这个错误。可以在命令前加-
如:

clean:
-mkdir src
-rm *.o # 删除所有.o文件,如果不存在,不用管,往下继续
-rm demo # 删除demo文件

回显问题

make会先在shell打印我们的命令,然后才会执行,我们如果不想让它打印我们的命令,需要在前面加上@

all:
@echo hello

命令包和eval

eval的作用是把一段文本当作makefile内容$(eval $(text))

define var = 
targets:
@echo hello
endef
$(eval $(var))

与之类似的出现过的概念叫命令包,就是定义一个多行变量,变量里的内容是一些命令。

define var =  
@echo hello
@echo world
@echo 3
endef

all:
$(var)

注意:需要区分这两者,一个是把文本当makefile里的内容,一个只是把文本当作一堆命令,并不能解析为目标依赖。

命令执行调用shell

make在执行命令的时候是调用/bin/sh来执行的,每一行命令都会调用一个shell来执行。
这样你在shell里定义的变量就无法被其他shell使用,如果我们想让多个命令在同一个shell里运行,就需要把它们写在同一行上,然后使用分号隔开。

.PHONY:print

print:
pwd; ls;cat demo.c

后缀替换

在makefile里有多种替换后缀的方式,我们在这里对他们进行区分

模式替换

这是变量的特性
语法:$(var:a=b),意思是将变量var的值当中每一项结尾的a替换为b,直接上例子。

files = main.cpp hello.cpp
objs := $(files:.cpp=.o) # main.o hello.o
# 另一种写法
objs := $(files:%.cpp=%.o)

subst

这是全局替换,会替换每一个匹配到的字符串

var1 = demo1.c demo2.c demo3.c 
var2 = demo1.c.c demo2.c demo3.c
result1 = $(subst .c,.o,$(var1))
result2 = $(subst .c,.o,$(var2))
all:
@echo $(result1) # demo1.o demo2.o demo3.o
@echo $(result2) # demo1.o.o demo2.o demo3.o

patsubst

这是模式替换,作用和变量的模式替换一样,都可以做到对后缀的替换。

var1 = demo1.c demo2.c demo3.c 
var2 = demo1.c.c demo2.c demo3.c
result1 = $(patsubst %.c,%.o,$(var1))
result2 = $(patsubst %.c,%.o,$(var2))
all:
@echo $(result1) # demo1.o demo2.o demo3.o
@echo $(result2) # demo1.c.o demo2.o demo3.o

MAKEFILES

一个特殊的环境变量,可能会影响正常执行。详情见陈浩老师的《跟我一起写Makefile》