最近总是涉及Makefile,说说自己的感悟,现在大的工程Makefile都写好了,或者使用Cmake或者automake生成Makefile,如果要优化,也是看懂即可按自己的想法修改,但是如果需要自己写一个小的测试程序,还需自己懂如何写Makefile,从今天开始做一个Makefile总结,每有所学就记录在此。虽说网上多的是,但也不能全都照搬,我的目的是会用,而不是开培训班上课,但自己写下来带有自己思考的才能是自己的东西。
全程复制:爱编程的大丙,大佬牛逼。
1. Makefile规则
target1, target2 ... : depend1, depend2, ...
comand1
comand2
- command:前面需要一个tab缩进
- target:执行command后可以生成一个和目标同名的文件(也可以不生成文件,因为command可能只是一个动作,这样的目标为伪目标)
【注】target可以有多个,因为comand也可以有多个
例子
#多个目标,多个命令
app1,app2:a.c b.c c.c
gcc -o app1 a.c b.c
gcc -o app2 b.c c.c
2. Makefile工作原理
2.1 规则的执行
先从一个例子开始:
# makefile
# 规则之间的嵌套
# 规则1
app:a.o b.o c.o
gcc a.o b.o c.o -o app
# 规则2
a.o:a.c
gcc -c a.c
# 规则3
b.o:b.c
gcc -c b.c
# 规则4
c.o:c.c
gcc -c c.c
总结一下结论:
- 执行make后,makefile会去从Makefile中找到第一条规则,第一条规则中的命令执行的前提是依赖全都存在。
- 如果第一条规则中的依赖不存在,他就会去找哪条命令能生成需要的依赖,知道所有的依赖都有了。
- 如果要执行Makefile中非第一条规则,就要把要那条规则的目标写到make命令后面(比如make b.o)。
2.2 文件时间戳
还是看这个例子:
# makefile
# 规则之间的嵌套
# 规则1
app:a.o b.o c.o
gcc app.o a.o b.o c.o -o app
# 规则2
a.o:a.c
gcc -c a.c
# 规则3
b.o:b.c
gcc -c b.c
# 规则4
c.o:c.c
gcc -c c.c
如果先执行:
make
后修改了文件中的b.c,然后再执行
make
那么,这时候就会先执行规则3,然后再执行规则1。
问题:第二次执行make的时候,明明第一条规则的目标实现比依赖要新,按理说不应该去执行规则2了呀,自己写个小程序实验目标是实现以下效果,Makefile与上述例子相同。
在执行完一遍make后。我更改b.c,再次make,后执行结果如下:
可以验证,Make在检查第一条规则时,看当前的依赖是否有依赖,如果有,就会递归的检查生成第一条规则依赖的规则是否满足“目标比依赖新”的要求。
2.3 自动推导
Makefile会会使用默认的编译规则编译.c文件,所以在写依赖时只需要写*.o,Makefile就会为这个 .o 寻找合适的源文件。
3. 变量
Makefile中有三种,分别为自定义变量,预定义变量,自动变量。
3.1 自定义变量
使用方法:
- 定义方法:变量名=变量值
- 使用方法:$(变量名)
3.2 预定义变量
Makefile中有些变量是预定义的,一般都是大写的,用户可以直接使用,请参考爱编程的大丙博客。
下面是其中的一个例子:
obj=add.o div.o main.o mult.o sub.o
target=calc
CFLAGS=-O3 # 代码优化
$(target):$(obj)
$(CC) $(obj) -o $(target) $(CFLAGS)
上面说预定义代码不用定义,但上面的例子不也是定义了一遍CFLAGS嘛,因为Makefile中代码的定义和赋值是在一起的。
3.3 自动变量
自动变量很重要,用于表示规则中的目标和依赖文件,只能在某条规则的命令中使用。
variable | implication |
---|---|
$* | 表示目标文件的名称,不包含目标文件的扩展名 |
$+ | 表示所有的依赖文件,这些依赖文件之间以空格分开,按照出现的先后为顺序,其中可能包含重复的依赖文件 |
$< | 表示依赖项中第一个依赖文件的名称 |
$? | 依赖项中,所有比目标文件时间戳晚的依赖文件,依赖文件之间以空格分开 |
$@ | 表示目标文件的名称,包含文件扩展名 |
$^ | 依赖项中,所有不重复的依赖文件,这些文件之间以空格分开 |
下面是一个小例子:
calc:add.o div.o main.o mult.o sub.o
gcc $^ -o $@
4. 模式匹配
在这只写一个例子,看懂了就行,用到了在研究,一般用到的不多。
# 模式匹配 -> 通过一个公式, 代表若干个满足条件的规则
# 依赖有一个, 后缀为.c, 生成的目标是一个 .o 的文件, % 是一个通配符, 匹配的是文件名
%.o:%.c
gcc $< -c