————————————————————————
小编写在前面的话:
Makefile总是让人一头雾水,这次来做个了结吧!
为什么写
一句话小结Makefile作用:去繁存简,挑新编译。
减去繁琐的编译指令,写完Makefile后,只需要用命令行工具(windows用cmd)进入到Makefile的同级目录,输入make即可开始编译。如果依赖中有一个文件更新了,则重新执行这条命令,大大缩短编译时间。
如何看懂
Makefile的结构大体分为两个模块:赋值、执行语句:
1.赋值
Makefile中有很多赋值语句,有”=”的就是赋值家族的一员。我们从c语言的逻辑入手,Makefile的赋值和c逻辑类似,就是:目标=参数。把A赋值给B,则A为参数,B为目标。
要注意以下几种不同赋值符号的含义:
符号 | 含义 |
---|---|
= | 基本赋值 |
:= | 覆盖之前的赋值 |
?= | 如果没有被赋值过则赋值 |
+= | 增加等号后面的赋值 |
不同在于,在c中赋值语句无外乎就是A=B,但是Makefile中可以将赋值和其他功能函数写成一句,大大减少了代码量。下面举两个栗子感受一下:
栗子1:赋值+宏定义
Makefile中的宏定义相当于在头文件中定义全局变量#define xxx,有几种写法都可以达到宏定义的目的:
Makefile | C语言 |
---|---|
-D A=B | #define A B |
-D FLAG=true | #define FLAG true |
-D FLAG | #define FLAG 1 |
结合上赋值语句,如CFLAGS += -D A,意思就是将A定义成一个宏,然后将这个宏赋值给CFLAGS。
栗子2:赋值+函数
为了在赋值的时候使用一些特别的功能,比如提取文件名、字符串模式替换等,会使用到Makefile函数:
函数名 | 作用 |
---|---|
shell | 返回在shell环境中的执行结果 |
wildcard | 获取匹配模式的文件名 |
patsubst | 模式替换函数 |
strip | 去掉空格 |
… | … |
函数的具体使用方法可以在使用的时候查一查,在这里就不一一展开描述了。
比如cont1 := $(shell cat cont2) 就是将cont2的内容赋值给cont1(cat是shell命令)。
现在出现了一个奇怪的符号$,不仅如此,Makefile中你可能还会看到很多不明含义的符号@,*,^,<等等,莫慌,我们将在第二个大块“执行语句”内提及。
2.执行语句
首先抓住关键,执行语句的标志是”:”,大概的结构是:
target… : prerequisites …
command
讲话太多,不如实际解析一段代码:
.PHONY: clean
clean:
rm dir
其中clean是要生成的目标,rm dir是目标clean所需的代码。.PHONY声明了clean这个目标是个伪目标。所谓伪目标,就是在make的时候不会执行代码rm dir,而是在make clean的时候才会执行。
在Makefile里还可以执行shell脚本,如 LDIR=$(shell pwd) ,此时只是赋值,shell是函数名,pwd是参数,赋值给变量LDIR,当Makefile执行LDIR变量的时候(@eho LDIR),shell脚本才会被执行。
.PHONY指定了一个编译伪目标,一个Makefile可能会有多个伪目标,如果设置all为第一个目标,如:
.PHONY:all
all:
...
.PHONY:del
...
.PHONY:clean
...
则执行make就代表make all。也可以用make xxx来单独编译其中一个目标。
Makefile是从第一行开始执行的,当遇到嵌套依赖的时候,先执行最底层的依赖。比如A依赖B,B依赖C,那么在运行到要执行A的时候,会先执行C,再执行B,最后执行A。
听起来是不是不难,之所以有的同学觉得比较难理解,是因为搞不清语句中一些特殊符号的含义。
现在我们就来总结一下使用比较多的符号:
符号 | 含义 |
---|---|
@ | Makefile会将所执行的命令在屏幕上回显出来,如果在命令前加了@表示运行时不回显此命令。 |
$ | 展开定义的目标 |
$@ | 表示目标 |
$^ | 表示展开所有的依赖 |
$< | 表示展开第一个依赖 |
$? | 表示比目标还要新的依赖文件列表 |
… | … |
有了以上这些,我想看大部分的Makefile总不至于一头雾水啦。
如何写
能看懂Makefile之后,我们就可以仿写一些自己的Makefile。在这里,写Makefile还有一些规矩要说。
- Makefile中执行命令如果另起一行,必须以[tab]键开头。如果命令紧跟在依赖的冒号后面就不用。用小括号()将$后面的东东包起来。
- 当一条命令的返回码为成功,make会执行下一条命令,如果失败,make会中止执行。又似乎后我们并不希望它中止,就会在Makefile的命令行前加一个”-”号,意思是此命令不管成不成功都往下执行。
- 如果你的工程好大,也许会用到嵌套Makefile,就是在子目录中还有Makefile指定了该子目录下文件的编译规则,那么在总Makefile中还要执行子目录的make,如
Subsystem:
$(MAKE)-C 子目录名
————————————————————
小编写在结尾的话:
遇到难题不要放弃呀,如果你也在做类似的事情,欢迎给小编发私信交流!若上文小编有理解不对的地方,也欢迎指正!