1.概述
Makefile与Shell脚本类似,是一系列命令的集合。用于项目代码编译管理。其定义了一系列的规则来指定文件是否需要编译以及编译顺序,甚至进行更复杂的功能操作。
- 优点:
“自动化编译”
节省编译时间
一次编写,终身受益 - 要点:
“一个规则”
“两个函数”
“三个自动变量”
2.“一个规则”
目标:依赖条件
[Tab]命令 // 注:命令若另起一行,命令前必须为[Tab键]
目标:要生成的文件
依赖条件:
命令:
makefile1:
hello.o:hello.c
[一个Tab键]gcc -c hello.c -o hello.o
基本原则:
- 若想生成目标,检查规则中的依赖条件是否存在,如不存在,则寻找是否存在规则用来生成该依赖文件。
- 检查规则中的目标是否需要更新,必须先检查他的所有依赖,依赖中有任何一个被更新,则目标必须更新。
makefile2:
hello:hello.o
gcc hello.o -o hello
hello.o:hello.c
gcc -c hello.c -o hello.o
当存在多个文件联合编译生成一个可执行文件时,可对比出makefile1与makefile2的优劣。
makefile3 :直接将所有文件编译并链接
a.out:111.c 222.c 333.c
gcc 111.c 222.c 333.c -o a.out
makefile4 :分别将每个文件编译,然后将每个 .o 文件进行链接
a.out:111.o 222.o 333.o
gcc 111.o 222.o 333.o -o a.out
111.o:111.c
gcc -c 111.c -o 111.o
222.o:222.c
gcc -c 222.c -o 222.o
333.o:333.c
gcc -c 333.c -o 333.o
- 根据基本规则2,当多个文件只有一个或部分被修改,未被修改的文件并不需要被重新编译,当文件较多时makefile4会节省大量时间。
- 通常我们称a.out为终极目标,makefile会将第一个目标作为默认终极目标,所以必须把终极目标作为第一个目标,为打破此项弊端,makefile存在一个默认命令all(ALL),用来指定终极目标。
makefile5 :此时,目标的顺序不再受限。
all:a.out
a.out:111.o 222.o 333.o
gcc 111.o 222.o 333.o -o a.out
111.o:111.c
gcc -c 111.c -o 111.o
222.o:222.c
gcc -c 222.c -o 222.o
333.o:333.c
gcc -c 333.c -o 333.o
3.“两个函数”(便于进行程序扩展)
- src = $(wildcard *.c) ----- 找到当前目录下所有后缀为.c的文件,赋值给src。
- obj =
(
p
a
t
s
u
b
s
t
(patsubst %.c,%.o,
(patsubst(src)) -----把src变量里所有后缀为.c的文件替换成.o;将参数3中,包含参数1的部分,替换为参数2。此时,makefile5便可进行升级:
makefile6 :
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
all:a.out
a.out:$(obj)
gcc $(obj) -o a.out
111.o:111.c
gcc -c 111.c -o 111.o
222.o:222.c
gcc -c 222.c -o 222.o
333.o:333.c
gcc -c 333.c -o 333.o
我们生成了多个编译文件,Makefile存在一个清除目标文件的规则,规则如下:
clean:
rm a.out
更为稳健的做法是:.PHONY表示clean是一个伪目标;“-”表示出错依然执行。不成文的规定“clean”规则一般放在文件最后。
.PHONY:clean
clean:
-rm -rf a.out
makefile7 :
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
all:a.out
a.out:$(obj)
gcc $(obj) -o a.out
111.o:111.c
gcc -c 111.c -o 111.o
222.o:222.c
gcc -c 222.c -o 222.o
333.o:333.c
gcc -c 333.c -o 333.o
.PHONY:clean
clean:
-rm -rf $(obj) a.out
执行clean的命令为 “make clean”,以防万一,酿成大祸,建议先执行“make clean -n”,预执行一下,观察结果正确后,再执行“make clean”。
4.“三个自动变量”(便于进行程序扩展)
- $@:表示规则命令中的目标
- $^:表示规则中的所有依赖条件,组成一个列表,以空格隔开,如果该列表中存在重复项则消除重复项
- $<:表示规则命令中的第一个依赖条件;如果将该变量应用在模式规则中,它可将依赖条件列表中的依赖依次取出,套用模式规则。
在makefile7的基础上,引入自动变量:
makefile8 :
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
all:a.out
a.out:$(obj)
gcc $^ -o $@
111.o:111.c
gcc -c $< -o $@
222.o:222.c
gcc -c $< -o $@
333.o:333.c
gcc -c $< -o $@
.PHONY:clean
clean:
-rm -rf $(obj) a.out
5.模式规则
%.o:%.c
gcc -c $< -o $@
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
all:a.out
a.out:$(obj)
gcc $^ -o $@
%.o:%.c
gcc -c $< -o $@
.PHONY:clean #强制执行
clean:
-rm -rf $(obj) a.out
静态模式规则:表示对哪一个依赖条件套用模式规则
$(obj)%.o:%.c
gcc -c $< -o $@
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
all:a.out
a.out:$(obj)
gcc $^ -o $@
$(obj)%.o:%.c
gcc -c $< -o $@
%.o:%.s
gcc -S $< -o ...
.PHONY:clean #强制执行
clean:
-rm -rf $(obj) a.out
伪目标:.PHONY:clean all #强制执行
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
c_flags = -Wall -g
all:a.out
a.out:$(obj)
gcc $^ -o $@ $c_flags
$(obj)%.o:%.c
gcc -c $< -o $@ $c_flags
%.o:%.s
gcc -S $< -o ...
.PHONY:clean #强制执行
clean:
-rm -rf $(obj) a.out
6.附录
= 与 :=
- “=” : make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值
- “:=”:表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值
总结
= 是最基本的赋值回
:= 是覆盖之前的值
?= 是如果答没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值