Makefile学习笔记 | 天一阁

Makefile学习笔记

Make 是自动构建工具。根据依赖关系,检查文件的更新时间,一旦有新的依赖文件,就把木匾文件重新构建一次。最早是贝尔实验室1976年开发的,后来GNU在标准make的基础上,增加了一些拓展,目前Linux下的make主要是GNU的make。

目标文件Target

从Make的执行逻辑写在makefile中, makefile由一些列的规则组成。简单的说,就是有个目标文件,如果依赖文件存在,则根据命令去生成目标文件。如果依赖文件不存在,则去找生成依赖文件的的指令。

1
2
<target> : <prerequisites>
[tab] <commands>

要说其实逻辑上不是很难理解,但是为了make可以执行更复杂的逻辑,就有大量的内置变量、函数、特殊符号,就把一个很直白的,顺序执行的脚本变成了像天书一样的东西。

如果Make命令运行时没有指定目标,默认会执行Makefile文件的第一个目标。如果指定**.DEFAULT_GOAL**变量,则构建DEFAUTL_GOAL所指定的目标。

.PHONY: 伪目标,声明.PHONY: clean是"伪目标"之后,make就不会去检查是否存在一个叫做clean的文件,而是每次运行都执行对应的命令。

在命令的前面加上@,就可以不打印命令

%是makefile里面的通配符。使用匹配符%,可以将大量同类型的文件,只用一条规则就完成构建。

变量

自定义变量
1
2
3
4
VARIABLE = value # 在执行时扩展,允许递归扩展。
VARIABLE := value # 在定义时扩展。
VARIABLE ?= value # 只有在该变量为空时才设置值。
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
2
reverse = $(2) $(1)
foo = $(call reverse,a,b) #此函数可以交换两个变量的顺序

eval:此函数可以生成一段makefile代码。这里经常出现多个$$连用。

参考makefile中常用函数

其他头疼问题

  1. order-only依赖

order-only依赖,用管道符号接在prerequisites后面,主要的作用是第一次生成target时才需要生成这些依赖。比如创建目录。参考这篇https://blog.csdn.net/Swartz2015/article/details/79828841

  1. gcc生成依赖

头文件修改后,也要重新编译。但是一般都是%.o:%.c模式,也就是说只关心.c文件,这个有可能导致问题。但是为了简化makefile编写,gcc可以生成.d文件包含了所有依赖的头文件。然后makefile再通过include语句把.d文件引用进来,就能做到头文件变化时,对应的依赖要重新编译。参考这篇还有这篇