Makefile基础入门
第1章 Makefile快速入门
基础概念
make :项目构建工具——用于管理文件的更新 Makefile:规则文件,告诉make如何进行编译与管理 Makefile(取名makefile也行)其实就是一个脚本文件。
快速入门
- 创建文本文档——文件名Makefile
- #代表注释
- 显示规则:一条显示规则由以下构成
1
2
|
目标文件:依赖文件 [Tab键]指令 |
示例: 1)首先我们新建一个文件夹,在该文件夹内写一个hello.cpp文件 2)我们新建一个Makefile文件。 3)在Makefile内第1个文件通常是我们的目标文件。 4)显然,在下面的文件中我们写上了4条显示规则。Makefile默认情况下会把第一条显示规则当作最终目标,也就是说,如果完成了第一条显示规则,那么Makefile是有可能不执行后面的显示规则的。可以通过ALL命令来指示最终目标:ALL hello,这样就无需将最终目标放在文件开头了。
1
2
3
4
5
6
7
8
9
10
11
|
hello:hello.o g++ hello.o -o hello hello.o:hello.s g++ -c hello.s -o hello.o hello.s:hello.i g++ -S hello.i -o hello.s hello.i:hello.cpp g++ -E hello.cpp -o hello.i |
- 伪目标 .PHONY:目标名(可以任意命名),使用伪目标指令就会执行目标后面的命令。
1
2
3
|
.PHONY: clean: rm -rf hello.o hello.s hello.i |
示例:执行clean命令
1
|
make clean |
变量的使用
变量=(替换) 变量+=(追加) 变量:=(常量) 使用变量——$(变量名)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
TARGET=hello OBJ=hello.o $(TARGET):$(OBJ) g++ hello.o -o hello hello.o:hello.s g++ -c hello.s -o hello.o hello.s:hello.i g++ -S hello.i -o hello.s hello.i:hello.cpp g++ -E hello.cpp -o hello.i .PHONY: clean: -rm -rf hello.o hello.s hello.i(rm前面加-表示执行过程中出错了也要继续往下执行) |
隐含规则
%.c文件表示任意的.c文件,%.o表示任意的.o文件。
通配符(自动变量 )
1
2
3
|
$@ 表示所有的目标文件 $^ 表示所有的依赖文件 $< 所有的依赖文件的第一个文件 |
第2章 Makefile详解
1个基本原则
- 若想生成目标,检查规则中的依赖条件是否存在,若不存在,则检查是否有规则用来生成该文件。
- 检查规则中的目标是否需要更新,必须先检查他的所有依赖,依赖中有任意一个被更新,则目标必须被更新(目标更新时间必须晚于依赖文件的更新时间,否则就会更新目标)。
2个函数
wildcard函数
1
2
3
|
src=$(wildcard *.c) 或者 src=$(wildcard ./*.c) |
src是Makefile文件的一个变量,Makefile只有一种变量类型字符串类型。 wildcard是一个函数,函数名意思是通配符。 以上函数语句的意思就是把当前目录下所有.c文件提取出来作为一个列表赋值给src。
patsubst函数
patsubst是patten substitude的缩写,匹配替代的意思。
1
|
obj=$(patsubts %.c, %.o, $(src)) |
将参数3中,包含参数1的部分,替换为参数2。 比如src = add.c sub.c div.c 则obj =add.o sub.o div.o
3个自动变量
@:在规则的命令中,表示规则中的目标@:在规则的命令中,表示规则中的目标^:在规则的命令行中,表示所有的依赖条件 $<:在规则的命令中,表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依赖条件中的依赖依次取出,套用模式规则。
注意:在一条规则中,$@只能用于命令行,而不能用于目标文件和依赖文件.看不懂这句话就先忽略
假设我们有Makefile文件内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
src=$(wildcard *.c) # add.c sub.c div.c main.c obj=$(patsubts %.c, %.o, $(src)) # add.o sub.o div.o main.o ALL:a.out a.out:$(obj) gcc $(obj) -o a.out add.o:add.c gcc -c add.c -o add.o sub.o:sub.c gcc -c sub.c -o sub.o div.o:div.c gcc -c div.c -o div.o main.o:main.c gcc -c main.c -o main.o clean: -rm -rf $(obj) a.out |
通过自动变量我们可以做出如下替换:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
src=$(wildcard *.c) # add.c sub.c div.c main.c obj=$(patsubts %.c, %.o, $(src)) # add.o sub.o div.o main.o ALL:a.out #在下面这条规则中, #目标文件是a.out,所以在命令行中$@的值就是a.out #依赖文件是$(obj)——值为add.o sub.o div.o main.o,所以在命令行中$^的值就是以上的 4 个文件 a.out:$(obj) gcc $^ -o $@ #在下面的这条规则中,目标文件的值是add.o,依赖文件的值是add.c #所以$<的值就是add.c,$@的值就是add.o,这里由于只有一个依赖文件,所以$<与$^的取值是一样的,我们使用$< add.o:add.c gcc -c $< -o $@ sub.o:sub.c gcc -c $< -o $@ div.o:div.c gcc -c $< -o $@ main.o:main.c gcc -c $< -o $@ clean: -rm -rf $(obj) a.out |
现在,你知道$@为什么不能用于目标文件和依赖文件的值了吧。因为以上三个自动变量的值就取决于目标文件和依赖文件的值。
模式规则
现在,我们要求再添加进一个功能,我们要添加mul.c文件实现乘法功能。 那么,我们现在也就必须要修改我们的Makefile文件。 但是我们想要实现的最终目标是,添加进新的文件时,不用修改我们的Makefile文件,这就需要用到模式规则。 %.c文件表示任意的.c文件,%.o表示任意的.o文件。 所以,在Makefile文件中,下面的几条规则我们可以进行替换
1
2
3
4
5
6
7
8
|
add.o:add.c gcc -c $< -o $@ sub.o:sub.c gcc -c $< -o $@ div.o:div.c gcc -c $< -o $@ main.o:main.c gcc -c $< -o $@ |
我们只用一条规则就可以替换上面的规则了
1
2
|
%.o:%.c gcc -c $< -o $@ |
请你思考,在这里为什么不能使用*.c而是必须使用%.c?为什么不能使用*.o而是必须使用%.o?也就是说,通配符*与%的区别是什么? 这样,我们添加新的mul.c文件时,通过模式规则我们就不用修改Makefile文件了。
静态模式规则
$(obj):%.o:%.c 相当于在模式规则的前面加上了个前缀,指定了(obj)应该要套用的模式规则。假设有以下场景:下面有两条模式规则都能产生.o文件,(obj)应该要套用的模式规则。 假设有以下场景:下面有两条模式规则都能产生.o文件,(obj)应该要套用的模式规则。假设有以下场景:下面有两条模式规则都能产生.o文件,(obj)应该套用哪天模式规则呢?这里就产生了歧义。需要用到静态模式规则。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
src=$(wildcard *.c) # add.c sub.c div.c main.c obj=$(patsubts %.c, %.o, $(src)) # add.o sub.o div.o main.o ALL:a.out a.out:$(obj) gcc $(obj) -o a.out %.o:%.c gcc -c $< -o $@ %.o:%.s gcc -S $< -o $@ clean: -rm -rf $(obj) a.out |
修改如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
src=$(wildcard *.c) # add.c sub.c div.c main.c obj=$(patsubts %.c, %.o, $(src)) # add.o sub.o div.o main.o ALL:a.out a.out:$(obj) gcc $(obj) -o a.out $(obj):%.o:%.c gcc -c $< -o $@ %.o:%.s gcc -S $< -o $@ clean: -rm -rf $(obj) a.out |
from:https://blog.nowcoder.net/n/16b8c4e009454abda117661f9bfbc212