当前位置: 首页 > news >正文

【把Linux“聊”明白】自动化构建-make/Makefile详解

在这里插入图片描述

自动化构建-make/Makefile详解

友情专栏:【把Linux“聊”明白】


文章目录

  • 自动化构建-make/Makefile详解
  • 前言
  • 一、make/Makefile是什么?
  • 二、make/Makefile的基本概念
    • **依赖关系和依赖方法说明**
    • **项目清理**
    • **什么叫做总是被执行?**
  • 三、 推导过程
  • 四、“高级版”的 Makefile
    • **代码**
    • 逐行讲解


前言

在Linux开发环境中,我们经常需要编译和构建复杂的项目。手动一个个编译源文件不仅效率低下,而且容易出错。这时候,make和Makefile就成为了每个Linux开发者必须掌握的利器。本文将带你从零开始,深入理解make和Makefile的工作原理,并通过实战案例展示如何编写高效的自动化构建脚本。


一、make/Makefile是什么?

简单来说,make是一条命令,Makefile是一个文件,两个搭配使用,完成项目自动化构建。
详解:
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
makefile带来的好处就是⸺“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具。

二、make/Makefile的基本概念

首先,建立一个Makefile文件

touch Makefile # Makefile/makefile都可以,我们习惯于Makefile

然后,保证你有个mypro.c的c文件,然后对Makefile写入:

mypro:mypro.cgcc mypro.c -o mypro # 前面的空格是一个tab的结果

依赖关系和依赖方法说明

在这里插入图片描述
即mypro依赖于mypro.c,而gcc myproc.c -o myproc 正是这种依赖方法。

在对Makefile写入上述依赖关系与依赖方法之后,我们就可以直接使用make命令了。

在这里插入图片描述

上面我们只是完成了Makefile的冰山一角,有个基础的认识。
我们可以用Makefile快速生成可执行,那有没有快速清理项目的呢?

项目清理

我们可以在已经有的Makefile再进行增加:

mypro:mypro.cgcc mypro.c -o mypro .PHONY:clean
clean:  # 可以没有依赖关系rm -f myproc

有了上面的Makefile,我们就可以进行项目清理了:
像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令⸺make clean,以此来清除所有的目标文件,以便重编译。

在这里插入图片描述

.PHONY **
但是一般我们这种clean的目标问文件,我们将它设置为伪目标,用.PHONY修饰,伪目标的特性是
总是被执行的**。
我们也可以对第一组依赖关系用.PHONY修饰,来看看效果:
未修饰之前:

在这里插入图片描述

修饰之后:

在这里插入图片描述
在这里插入图片描述

有这些理解,我们来看看什么叫做总是被执行?

什么叫做总是被执行?

我们要知道,在编译的时候,默认老代码(以前编译过)是不会别重新编译的,很好理解,但是编译器是如何知道你是老代码还是新代码/更改过的代码。
我们知道:文件 = 内容 + 属性,我们可以用stat来查看文件的属性。

在这里插入图片描述
Modify: 内容变更,时间更新
Change:属性变更,时间更新
Access:常指的是文件最近一次被访问的时间。在Linux的早期版本中,每当文件被访问时,其atime都会更新。但这种机制会导致大量的IO操作。具体更新原则,不做过多解释

有了上面的了解,可以,对于每个文件的属性中都有其’‘时间’'属性,我们改变了文件的内容,它的Modify时间一定会变,所以通过Modify时间来进行对比判断它是老代码还是新代码/更改过的代码。和谁对比呢,就和对应的二进制文件中的相对应的时间属性进行对比。

但是,有了.PHONY,它不管老代码还是新代码/更改过的代码,都会重新编译,可见:
.PHONY会让make忽略源文件和可执行目标文件的M时间对比

三、 推导过程

我们知道,C语言程序从.c文件到可执行文件会经过预处理、编译、汇编、链接,现在我们可以依次在Makefile中实现它:

  1 mypro:mypro.o                                                                                                                   2     gcc mypro.o -o mypro3 mypro.o:mypro.s4     gcc -c mypro.s -o mypro.o5 mypro.s:mypro.i6     gcc -S mypro.i -o mypro.s7 mypro.i:mypro.c8     gcc -E mypro.c -o mypro.i9                                                                                                  10 .PHONY:clean11 clean:12     rm -f *.i *.s *.o mypro  

执行make:

在这里插入图片描述

可见这样写也是可以的,那是怎么推导的呢?

当执行make命令时:
在这里插入图片描述
详细图解:
在这里插入图片描述

接下来,我们来总结分析一下make 是如何工作的,我们只 make 命令之后。那么:

  1. make 会在当前目录下找名字叫 “Makefile”“makefile” 的文件。

  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,它会找到 mypro 这个文件,并把这个文件作为最终的目标文件。

  3. 如果 mypro 这个文件不存在,或者 mypro 所依赖的 mypro.o 文件的修改时间要比 mypro 这个文件新,那么,它就会执行后面所定义的命令来生成 mypro 这个文件。

  4. 如果 mypro 所依赖的 mypro.o 文件不存在,那么 make 会在当前文件中找目标为 mypro.o 文件的依赖性,如果找到则再根据那个规则生成 mypro.o 文件。(这有点像一个堆栈的过程)

  5. 当然,你的 .c 文件和 .h 文件是存在的啦,于是 make 会生成 mypro.o 文件,然后再用 mypro.o 文件完成 make 的终极任务,也就是生成可执行文件 mypro 了。

  6. 这就是整个 make 的依赖性,make 会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。

  7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么 make 就会直接退出,并报错。而对于后定义的命令的错误,或是编译不成功,make 根本不理。

  8. make 只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不存在,那么对不起,我就不工作啦。

四、“高级版”的 Makefile

有了上面一大串的铺垫,我们上面的Makefile文件只是一个较为简单的Makefile,只适合有一个源文件的时候使用,接下来,我要在此基础上在进行升级(适用于多个源文件的情况):

代码

BIN=proc.exe        # 定义变量:最终生成的可执行文件名
CC=gcc              # 定义变量:使用的编译器#SRC=$(shell ls *.c)     # 方式一:用 shell 命令获取所有 .c 文件名
SRC=$(wildcard *.c)      # 方式二:用 make 自带函数 wildcard 获取所有 .c 文件OBJ=$(SRC:.c=.o)         # 把所有 .c 文件替换成对应的 .o 文件(目标文件列表)LFLAGS=-o                # 链接选项(用于生成可执行文件)
FLAGS=-c                 # 编译选项(用于生成目标文件)
RM=rm -f                 # 定义删除命令# === 构建目标规则 ===
$(BIN):$(OBJ)@$(CC) $(LFLAGS) $@ $^         # 第一个@:不回显命令@echo "linking ... $^ to $@"# === 模式规则:编译每个 .c 文件成 .o 文件 ===
%.o:%.c@$(CC) $(FLAGS) $<@echo "compiling ... $< to $@"# === 清理规则 ===
.PHONY:clean
clean:$(RM) $(OBJ) $(BIN)# === 测试输出规则(非编译) ===
.PHONY:test
test:@echo $(SRC)@echo $(OBJ)

逐行讲解

定义变量

BIN=proc.exe
CC=gcc
SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)
  • BIN:最终生成的可执行文件名
  • CC:指定编译器为 gcc
  • SRC:自动收集当前目录下所有 .c 文件
  • OBJ:把 .c 扩展名替换为 .o,即生成目标文件列表

例如,当前目录中有:

main.c util.c

则:

SRC = main.c util.c
OBJ = main.o util.o

编译并链接

$(BIN):$(OBJ)@$(CC) $(LFLAGS) $@ $^

解释:

  • 目标:proc.exe
  • 依赖:main.o util.o
  • 命令:使用 gcc 链接所有 .o 文件生成 proc.exe
  • $@:代表目标(这里是 proc.exe
  • $^:代表所有依赖文件(这里是 main.o util.o

模式规则

%.o:%.c@$(CC) $(FLAGS) $<

这是 模式匹配规则

  • % 代表任意匹配部分(相同名字的 .c.o
  • $<:代表第一个依赖文件(即 .c 文件)
  • 命令会自动把每个 .c 编译成 .o

等价于:

main.o: main.cgcc -c main.cutil.o: util.cgcc -c util.c

清理规则

.PHONY: clean
clean:$(RM) $(OBJ) $(BIN)
  • .PHONY:声明伪目标(表示 clean 不是文件名)
  • $(RM):删除命令,这里是 rm -f
  • 作用:清除生成的目标文件和可执行文件。

执行:

make clean

即可清空中间文件。

测试规则

.PHONY: test
test:@echo $(SRC)@echo $(OBJ)

输出当前检测到的 .c.o 文件,用于调试验证。

总结
这个 Makefile 利用了 变量 + 通配符 + 模式规则,实现了自动化、多文件可扩展的编译流程,可以认真学习学习。


如果本文对您有启发:
点赞 - 让更多人看到这篇硬核技术解析 !
收藏 - 实战代码随时复现
关注 - 获取Linux系列深度更新
您的每一个[三连]都是我们持续创作的动力!

请添加图片描述

http://www.dtcms.com/a/589405.html

相关文章:

  • 软考 系统架构设计师之考试感悟4
  • 广州天河 网站建设乌市网站建设为
  • 52_AI智能体运维部署之使用Flask蓝图模块化系统监控服务
  • 【2025-11-07】软件供应链安全日报:最新漏洞预警与投毒预警情报汇总
  • Linux系统笔记--Base
  • RHCE配置主从服务器的实验
  • 中国十大热门网站排名网页加载不出来怎么办
  • Labview封装exe程序
  • 网站用视频做背景音乐小程序商城货源怎么找
  • C/C++输入输出初级(二) (算法竞赛)
  • Windows导入大型sql文件到mysql
  • K8S RD: Kubernetes核心概念与运维实践详解
  • 营销型企业网站测评表wordpress汽车主题
  • Java中文件操作和IO
  • MapTalks:国产轻量化二三维一体化GIS引擎
  • 做html网站wordpress divi安装
  • JS 表单处理与数据校验实战指南:构建安全、流畅的交互体验
  • php网站开发程序编译软件招商网站建设免费
  • 在Rsbuild中使用Rsdoctor
  • 临沂学做网站做网站购买什么软件
  • AIGC|上海AI优化企业新榜单与选择指南
  • 26.分布式系统链路追踪
  • 《Redis应用实例》Java实现(29):优先队列
  • 【FPGA】使用移位和38译码器原理实现LED流水灯
  • 哪些网站用django做的南昌网站设计网站开发
  • GraphQL:让前端自己决定要什么数据
  • 基于非负矩阵分解的复杂网络社区检测研究综述
  • 怎么让网站绑定域名访问广州建筑公司招聘信息
  • Webpack 打包体积优化:让应用更轻量、更高效
  • Webpack 优化:构建速度与包体积的双重提升