大型工程会将工程中的多个源文件,按照类型、功能、模块分别放在若干目录中,Makefile文件定义了一系列的规则来指定哪些文件需要先编译,哪些文件后编译,哪些文件需要重新编译,甚至进行更复杂的功能操作。
Makefile带来的好处就是”自动化编译“,一旦写好,只需要一个make命令,整个工程完全自动编译,极大提高软件开发的效率。
make是一个命令工具,是解释makefile文件中指令的命令工具。
1.1 文件命名和规则
makefile
或者Makefile
makefile 规则
一个Makefile文件中可以有一个或多个规则。
目标... : 依赖...
命令(shell命令)
...
-
目标:最终想要生成的文件(伪目标除外)
-
依赖:生成目标所需要的文件或是目标
-
命令:通过执行命令对依赖操作生成目标(命令前必须Tab缩进)
Makefile中的其他规则都是为第一条规则服务的
1.2 工作原理
#Makefile1
app:sub.c add.c mult.c div.c main.c
gcc sub.c add.c mult.c div.c main.c -o app
-
命令在执行之前,需要检查规则中的依赖是否存在
-
如果存在,执行命令
-
如果不在,向下检查其他规则,检查有没有规则是用来生成这个依赖的,如果找到了,就执行该规则中的命令。
-
-
检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间
-
如果依赖的时间比目标的时间晚, 需要重新生成目标
-
如果依赖的时间比目标的时间早,目标不需要更新,对应规则中的命令不需要被 执行
-
#Makefile2
app:sub.o add.o mult.o div.o main.o
gcc sub.o add.o mult.o div.o main.o -o app
sub.o:sub.c
gcc -c sub.c -o sub.o
add.o:add.c
gcc -c add.c -o add.o
mult.o:mult.c
gcc -c mult.c -o mult.o
div.o:div.c
gcc -c div.c -o div.o
main.o:main.c
gcc -c main.c -o main.o
1.3 变量
自定义变量
- 变量名 = 变量值 val = hello
预定义变量
AR
: 归档维护程序的名称, 默认为ar
CC
: C 编译器的名称,默认值为 ccCXX
: C++ 编译器的名称,默认值为 g+$@
: 目标的完整名称$<
: 第一个依赖文件的名称$^
: 所有的依赖文件
获取变量的值
$(变量名)
app : main.c a.c b.c
gcc -c main.c a.c b.c
app : main.c a.c b.c
$(cc) -c $^ -o $@
1.4 模式匹配
%.o : %.c
%
: 通配符,匹配一个字符串- 两个
%
匹配同一个字符串
#Makefile3
src = sub.o add.o mult.o div.o main.o
target = app
$(target) : $(src)
$(CC) $(src) -o $(target)
%.o:%.c
gcc -c $< -o $@
1.5 函数
$(wildcard PATTERN...)
- 功能:获取指定目录下指定类型的文件列表
- 参数:PATTERN 指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔
- 返回:得到的若干个文件的文件列表,文件名之间使用空格间隔
$(wildcard *.c ./sub/*.c) #返回值格式: a.c b.c c.c d.c e.c f.c
$(patsubst <pattern>, <replacement>, <text>)
- 功能:查找
中的单词(单词以“空格”、“Tab”或“回车”、“换行”分隔)是否符合模式,如果匹配的话,则以替换。 - 可以包括通配符
%
,表示任意长度的字串。如果中也包含%
,那么,中的这个%
将是中的那个% 所代表的字串。(可以用\
来转义,以\%
来表示真实含义的%
字符) - 返回:函数返回被替换过后的字符串
$(patsubst %.c, %.o, x.c bar.c) #返回值格式: x.o bar.o
#Makefile4
src = $(wildcard ./*.c)
objs = $(patsubst %.c, %.o, $(src))
target = app
$(target) : $(objs)
$(CC) $(src) -o $(target)
%o : %c
$(CC) -c $< -o $@
伪目标
.PHONY : clean
clean :
rm $(objs)