Makefile学习笔记
1.Makefile是什么
当一个工程中的源文件数量太多时,我们可以使用Makefile文件定义一系列规则来指定哪些文件需要先编译或后编译,甚至重新编译。
简而言之,我认为Makefile可以实现自动化编译,只需要一个make命令,该项目的程序能实现完全自动编译,提高了软件开发的效率。
2.文件命名和规则
文件命名:Makefile 或者 makefile
规则:一个Makefile文件可以有一个或者多个规则
目标 :依赖
命令(shell命令)
app: sub.c mult.c div.c add.c main.c
gcc mult.c sub.c add.c div.c main.c -o app
app为目标文件,%.c 为依赖文件。通过gcc命令来连接生成app。
注意:Makefile中的其他规则一般为第一条规则服务。
下面是Makefile的另外一种写法:
app:sub.o div.o add.o mult.o main.o gcc sub.o div.o add.o mult.o main.o -o app sub.o:sub.c gcc -c sub.c -o sub.o div.o:div.c gcc -c div.c -o div.o add.o:add.c gcc -c add.c -o add.o mult.o:mult.c gcc -c mult.c -o mult.o main.o:main.c gcc -c main.c -o main.o
该写法可以提高编译的效率,当执行make命令时,会执行第一条规则,寻找依赖文件,如果找不到就会跳到其他规则中找相应的生成依赖文件。该写法的好处是:在已经编译好的前提下,当我更新了一个源文件时,我只会遍历并判定更新的源文件进行修改更新编译,对其他未修改源文件不做任何处理。而第一种写法可能需要遍历
所有源文件进行编译,效率会比第二种方法低一些,所以推荐使用第二种Makefile写法。
3.Makefile工作原理:
上面提到了一些:命令在执行前,需要检查规则中的依赖文件是否存在:
1.若存在,执行命令
2.若不存在,向下检查其他规则,检查有无一个规则是用来生成这个依赖的,如果找到了就执行该规则的命令
检测更新:在执行规则中的命令时,会比较目标和依赖文件的时间
1.若目标比依赖时间晚,目标不需要更新,对应规则中的命令不需要被执行。
2.若目标比依赖时间早,也就是依赖的时间比目标晚,说明依赖被修改了,需要重新生成目标。
这也就是为什么上述第二种方法更好的原因了,在检测更新的时候,只需要更新已被修改的源文件,效率提高。
4.变量、模式匹配、函数的用法
我们发现,前两种方法都需要写出源文件名称,如果有1000个源文件,那我们岂不是要写1000个?所以,为了减轻负担,Makefile引入了变量和模式匹配概念,我们先讲变量。
自定义变量
变量 名 = 变量值
预定义变量
AR: 归档维护程序的名称,默认值为ar
CC:C编译器的名称,默认值为cc
CXX:C++编译器的名称,默认值为g++
$@ : 目标的完整名称
$< : 第一个依赖文件的名称
$^ : 所有依赖文件
获取变量的值
$(变量名)
下面是变量的用法
src = sub.o add.o mult.o div.o main.o target = app $(target):$(src) $(CC) $(src) -o $(target) 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
在这里我们自定义了目标文件target和依赖文件target,通过变量来编写Makefile文件可以减轻一些敲代码工作。
然而我们发现,下面其他规则还是需要一一写清楚,代码工作量依旧很大,因此我们需要引入通配符和模式匹配的概念。
%.o : %.c %: 通配符,匹配一个字符串 两个%匹配的是同一个字符串 %.o :%.c gcc -c $< -o $@
完整的代码如下:
src = sub.o add.o mult.o div.o main.o target = app $(target):$(src) $(CC) $(src) -o $(target) %.o: %.c $(CC) -c $< -o $@
最后引入函数
$(wildcard PATTERN...)
功能:获取指定目录下指定类型文件列表
参数:PATTERN指的是某个或多个目录下的对应的某种类型的文件,若有多个目录,一般使用空格间隔。
返回:得到的若干个文件的文件列表,文件名之间使用空格间隔。
$(patsubst <pattern>,<replacement>,<text>)
功能:查找<text>中的单词 ,查看是否符合模式<pattern>,若匹配的话,就用<replacement>替换。
eg: $(patsubst %.c, %.o,x.c bar.c) 返回:x.o bar.o
下面是实际用法:
src = $(wildcard ./*.c)
objs = $(patsubst %.c, %.o,$(src))
target=app
$(target): $(objs)
$(CC) $(objs) -o $(target)
%.o : %.c
$(CC) $^ -o $@
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)