Make 是自动构建工具。根据依赖关系,检查文件的更新时间,一旦有新的依赖文件,就把木匾文件重新构建一次。最早是贝尔实验室1976年开发的,后来GNU在标准make的基础上,增加了一些拓展,目前Linux下的make主要是GNU的make。
目标文件Target
从Make的执行逻辑写在makefile中, makefile由一些列的规则组成。简单的说,就是有个目标文件,如果依赖文件存在,则根据命令去生成目标文件。如果依赖文件不存在,则去找生成依赖文件的的指令。
1 | <target> : <prerequisites> |
要说其实逻辑上不是很难理解,但是为了make可以执行更复杂的逻辑,就有大量的内置变量、函数、特殊符号,就把一个很直白的,顺序执行的脚本变成了像天书一样的东西。
如果Make命令运行时没有指定目标,默认会执行Makefile文件的第一个目标。如果指定**.DEFAULT_GOAL**变量,则构建DEFAUTL_GOAL所指定的目标。
.PHONY: 伪目标,声明.PHONY: clean
是"伪目标"之后,make就不会去检查是否存在一个叫做clean的文件,而是每次运行都执行对应的命令。
在命令的前面加上@,就可以不打印命令
%是makefile里面的通配符。使用匹配符%,可以将大量同类型的文件,只用一条规则就完成构建。
变量
自定义变量
1 | VARIABLE = value # 在执行时扩展,允许递归扩展。 |
自动变量
$@:目标的名字
$^:构造所需文件列表所有文件的名字
$<:构造所需文件列表的第一个文件的名字
$?:构造所需文件列表中更新过的文件
只能用于recipe中
函数
字符串函数
patsubst:替换字符串支持通配符,这里的通配符是百分号**%**
filter:过滤字符串,这里的通配符是百分号**%**
文件名函数
wildcard:查找符合条件的文件,通配符用星号*****
dir:取文件名的目录部分
suffix:取文件名的后缀部分
addprefix:给文件名添加前缀,一般是增加目录部分
addsuffix:给文件添加后缀
其他函数
if:$(if condition,then-part[,else-part])
这里的条件是看condition是否为空串,不是空串则为真
foreach:$(foreach var,list,text)
带入var循环执行text,结果会连接一起返回
shell:$(shell shell命令或脚本)
call:$(call variable,param,param,…)
通过call函数可以执行自定义的函数。自定义函数就是变量调用的基础上,增加参数。
1 | reverse = $(2) $(1) |
eval:此函数可以生成一段makefile代码。这里经常出现多个$$连用。
其他头疼问题
- order-only依赖
order-only依赖,用管道符号接在prerequisites后面,主要的作用是第一次生成target时才需要生成这些依赖。比如创建目录。参考这篇https://blog.csdn.net/Swartz2015/article/details/79828841
- gcc生成依赖
头文件修改后,也要重新编译。但是一般都是%.o:%.c模式,也就是说只关心.c文件,这个有可能导致问题。但是为了简化makefile编写,gcc可以生成.d文件包含了所有依赖的头文件。然后makefile再通过include语句把.d文件引用进来,就能做到头文件变化时,对应的依赖要重新编译。参考这篇还有这篇