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 $@

 

 

 

   

posted @   Halooo113  阅读(36)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示