makefile 作用
- 项目代码编译管理
- 节省编译项目时间
- 一次编写终身受益
运行规则
- 若想生成目标,检查规则中的依赖条件是否存在。如果不存在,则寻找是否有规则用来生成该依赖文件。
- 检查规则中的目标是否需要被更新,必须先检查它的所有依赖,依赖中有任何一个被更新,则目标必须被更新。
- 分析各个目标和依赖之间的关系
- 根据依赖关系自底向上执行命令
- 根据修改时间比目标新旧与否确定更新
- 如果目标不依赖任何条件,则执行对应命令,以示更新
 
一个最简单的makefile:
| 12
 
 | hello:hello.cgcc hello.c -o hello
 
 | 
考虑中间步骤:
| 12
 3
 4
 
 | hello:hello.ogcc hello.c -o hello
 hello.o:hello.c
 gcc hello.c-o hello.o
 
 | 
makefile使用
一个规则
多文件联编:
| 12
 
 | hello:hello.ogcc hello.c add.c sub.c div1.c -o hello
 
 | 
考虑到多文件编译的时间成本,应该先将个各个模块编译成.o目标文件,由目标文件链接成可执行文件。这样只有改动过的模块会被再次编译,其他的保持不变。
| 12
 3
 4
 5
 6
 7
 8
 
 | hello:hello.ogcc hello.o add.o sub.o div1.o -o hello
 hello.o:hello.c
 gcc -c hello.c -o hello.o
 sub.o:sub.c
 gcc -c add.c -o add.o
 div1.o:div1.c
 gcc -c div1.c -o div1.o
 
 | 
make只会认为第一行是自己的最终目标, 如果最终目标没有写在第一行, 通过ALL来指定;
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | ALL:hello
 hello.o:hello.c
 gcc -c hello.c -o hello.o
 add.o:add.c
 gcc -c add.c -o add.o
 sub.o:sub.c
 gcc -c sub.c -o sub.o
 div1.o:div1.c
 gcc -c div1.c -o div1.o
 
 hello:hello.o add.o sub.o div1.o
 gcc hello.o add.o sub.o div1.o -o hello
 
 | 
两个函数和clean
- src=$(wildcard ./*.c):匹配当前目录下的所有.c源文件, 赋值给变量src(与shell类似, 变量只有字符串类型)
 
- obj=$(patsubst %.c,%.o,$(src)):将参数3中包含参数1的部分替换为参数2
 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | src=$(wildcard ./*.c)obj=$(patsubst %.c,%.o,$(src))
 
 ALL:hello
 hello:$(obj)
 gcc $(obj) -o hello
 
 hello.o:hello.c
 gcc -c hello.c -o hello.o
 add.o:add.c
 gcc -c add.c -o add.o
 sub.o:sub.c
 gcc -c sub.c -o sub.o
 div1.o:div1.c
 gcc -c div1.c -o div1.o
 
 clean:
 -rm -rf $(obj) hello
 
 | 
- 执行make clean时务必加上-n参数检查, 避免把源码删掉
- clean相当于一个没有依赖条件的规则
- rm前面的横杠表示出错(文件不存在)仍然执行
三个自动变量和模式规则
三个自动变量:
- $@:在规则的命令中, 表示规则中的目标
- $^:在规则的命令中, 表示所有依赖条件
- $<:在规则的命令中, 表示第一个依赖条件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | src=$(wildcard ./*.c)obj=$(patsubst %.c,%.o,$(src))
 
 ALL:hello
 hello:$(obj)
 gcc $^ -o $@
 
 hello.o:hello.c
 gcc -c $< -o $@
 add.o:add.c
 gcc -c $< -o $@
 sub.o:sub.c
 gcc -c $< -o $@
 div1.o:div1.c
 gcc -c $< -o $@
 
 clean:
 -rm -rf $(obj) hello
 
 | 
模式规则:
鉴于上面的都是某个.o文件依赖于某个.c文件的形式, 可以将其总结为一个模式规则:
| 12
 
 | %.o:%.cgcc -c $< -o $@
 
 | 
关于$<:如果将该变量应用在模式规则中, 它可将依赖条件列表中的依赖项依次取出, 套用模式规则:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | src=$(wildcard ./*.c)obj=$(patsubst %.c,%.o,$(src))
 
 ALL:hello
 hello:$(obj)
 gcc $^ -o $@
 
 %.o:%.c
 gcc -c $< -o $@
 
 clean:
 -rm -rf $(obj) hello
 
 | 
加入了模式规则后, 当再加入新的模块, 比如mul模块, 不需要改动makefile就可以实现自动编译链接, 非常的方便.
扩展
| 12
 
 | $(obj)%.o:%.cgcc -c $< -o $@
 
 | 
- 加入伪目标(为了防止目录下的与clean和ALL的同名文件的干扰):
- 加入常用参数(-Wall, -I, -l, -L, -g), 形成最终版本:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | src=$(wildcard ./*.c)obj=$(patsubst %.c,%.o,$(src))
 
 myArgs=-Wall -g
 
 ALL:hello
 hello:$(obj)
 gcc $^ -o $@ $(myArgs)
 
 %.o:%.c
 gcc -c $< -o $@ $(myArgs)
 clean:
 -rm -rf $(obj) hello
 
 .PHONY:clean ALL
 
 | 
练习

makefile文件:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | src=$(wildcard ./src/*.c)obj=$(patsubst ./src/%.c,./obj/%.o,$(src))
 
 myArgs=-Wall -g
 inc_path=./inc
 
 ALL:hello
 hello:$(obj)
 gcc  $^ -o $@ $(myArgs)
 
 $(obj):./obj/%.o:./src/%.c
 gcc -c $< -o $@ $(myArgs) -I $(inc_path)
 
 .PHONY: ALL clean
 
 clean:
 -rm -rf ./obj/*.o hello
 
 | 
当文件名不叫makefile:
| 12
 
 | make -f m1make -f m1 clean
 
 |