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

【Linux】深入浅出 Linux 自动化构建:make 与 Makefile 的实用指南

🔥 脏脏a的技术站 🔥
 
「在代码的世界里,脏脏的技术探索从不设限~」

 

 

🚀 个人主页:脏脏a-CSDN博客

📌 技术聚焦:Linux 环境下 yum 与 vim 工具的实用技巧与深度解析
📊 文章专栏:Linux

🔗 上篇回顾:sudo 白名单配置与 GCC/G++ 编译器使用指南

在 Linux 开发中,makeMakefile是提升项目构建效率的神兵利器。从单个文件的小程序到百万行代码的大型工程,掌握它们能让你从重复的编译命令中解放出来。本文将带你从零开始理解make、makefile 的工作原理,并通过实战案例掌握其应用技巧。

目录

 

🎨一、背景:为什么需要 make/Makefile?

🧪二、核心概念:依赖关系与依赖方法

【案例】:一个简单的 C 项目

【问题】:文件名必须是makefile吗?

【问题】:如果打乱依赖关系的顺序会正常执行吗?

📝三、make 的工作原理:如何判断 “是否需要编译”?

【stat指令】

🔍四、伪目标与项目清理

🚧五、特殊符号

📋六、依赖关系缺失问题

🔗七、如何在使用make后不显示依赖方法

📌八、make工作原理总结


 

🎨一、背景:为什么需要 make/Makefile?

想象一下,你有一个由多个.c文件组成的项目,每次修改代码后都要手动执行gcc -c file1.cgcc -c file2.cgcc -o target file1.o file2.o…… 这样的重复劳动不仅低效,还容易出错。

make是一个命令工具Makefile是一个规则文件,二者配合实现了自动化编译:只需编写一次规则,后续执行make命令即可自动完成 “哪些文件需要编译、哪些需要重编译” 的判断,极大提升开发效率。

对于大型工程,会不会写 Makefile 甚至成为衡量工程师能力的一个侧面标准 —— 毕竟它能清晰管理 “文件依赖、编译顺序、清理逻辑” 等复杂场景。

🧪二、核心概念:依赖关系与依赖方法

makefile 的核心是 “依赖关系依赖方法”:

  • 依赖关系:描述 “目标文件” 依赖于哪些 “源文件”。例如,可执行文件hello依赖于目标文件hello.ohello.o依赖于汇编文件hello.s,以此类推。
  • 依赖方法:描述如何从 “依赖文件” 生成 “目标文件”(通常是编译命令)。

【案例】:一个简单的 C 项目

我们以输出 “hello Makefile!” 的小程序为例,逐步构建 Makefile。

【步骤 1】:编写 C 代码(hello.c

#include <stdio.h>
int main()
{printf("hello Makefile!\n");return 0;
}

【步骤 2】:编写 Makefile 规则

一个完整的 Makefile 规则格式为:

目标文件: 依赖文件依赖方法(编译命令,注意开头必须是Tab缩进)

针对hello.c,我们可以编写多层依赖的 Makefile:

# 最终可执行文件hello,依赖于hello.o
hello: hello.ogcc hello.o -o hello# 目标文件hello.o,依赖于hello.s
hello.o: hello.sgcc -c hello.s -o hello.o# 汇编文件hello.s,依赖于hello.i
hello.s: hello.igcc -S hello.i -o hello.s# 预处理文件hello.i,依赖于hello.c
hello.i: hello.cgcc -E hello.c -o hello.i

【步骤 3】:执行 make命令

在终端中输入make时,它会仅以 Makefile 中第一个定义的目标为起点,沿着该目标的完整依赖链(例如hello→hello.o→hello.s→hello.i→hello.c)执行构建。

整个过程中,make只会处理这个 “第一个目标” 及其所有依赖项(包括直接依赖和间接依赖),其他未被该依赖链关联的目标(即使在 Makefile 中定义)也不会被自动执行。

同时,它会通过比较 “目标文件” 与 “依赖文件” 的修改时间实现 “按需编译”:只有当依赖文件更新过(修改时间更新),才会重新编译对应的目标,否则直接跳过,大幅提升效率。

【问题】文件名必须是makefile吗?

make是命令,makefile是一个文件,当前目录下的文件

文件名不一定必须是 Makefile,但 make 命令有默认的文件名查找规则,常用的合法文件名有两种:

  1. Makefile(首字母大写)
  2. makefile(全小写)

这两个文件名是 make 命令的默认查找对象。当在终端执行 make 时,它会优先先在当前目录下寻找这两个文件,找到后按其中的规则执行构建。

【如果想用其他文件名怎么办?】

如果你的想将构建规则文件命名为其他名称(比如 mybuild),可以通过 make 的 -f 或 --file 参数指定文件名,例如:

make -f mybuild  # 告诉make使用mybuild文件作为规则文件

【为什么推荐用 Makefile?】

在实际开发中,更推荐使用 Makefile(首字母大写),原因是:

  • 它在目录中会更醒目(通常大写字母的文件会排在前面),方便开发者和其他开发者快速识别项目的构建规则文件。
  • 符合大多数开源项目的约定,增强代码的规范性和可读性。

总结:默认情况下,make 只认 Makefile 或 makefile,但通过 -f 参数可以指定任意文件名作为构建规则文件。


【问题】:如果打乱依赖关系的顺序会正常执行吗?

在 Makefile 中,规则的顺序不影响依赖关系的解析,因为 make 是基于 “依赖树” 的拓扑顺序来执行编译的,而非按照规则在文件中的书写顺序。

以提供的 Makefile 为例,即使将规则顺序打乱,比如:

# 汇编文件hello.s,依赖于hello.i
hello.s: hello.igcc -S hello.i -o hello.s# 最终可执行文件hello,依赖于hello.o
hello: hello.ogcc hello.o -o hello# 预处理文件hello.i,依赖于hello.c
hello.i: hello.cgcc -E hello.c -o hello.i# 目标文件hello.o,依赖于hello.s
hello.o: hello.sgcc -c hello.s -o hello.o

make 依然会自动梳理依赖关系的层级

  1. 要生成 hello,需要先有 hello.o
  2. 要生成 hello.o,需要先有 hello.s
  3. 要生成 hello.s,需要先有 hello.i
  4. 要生成 hello.i,需要先有 hello.c

最终会按照 hello.c → hello.i → hello.s → hello.o → hello 的正确顺序执行编译命令。

这是因为 make 的核心逻辑是 “先处理依赖项,再处理目标项”—— 它会递归地查找每个目标的依赖,直到找到最底层的源文件(如 hello.c),再从下往上依次执行编译。

因此,只要依赖关系的定义是正确的,规则在 Makefile 中的书写顺序可以任意调整make 都能正确识别并按依赖层级执行构建。

📝三、make 的工作原理:如何判断 “是否需要编译”?

make 的核心逻辑是比较 “目标文件” 和 “依赖文件” 的 “最近修改时间”

  • 如果 “依赖文件” 的修改时间晚于“目标文件”,说明依赖文件被更新过,需要重新编译生成目标文件。
  • 如果 “目标文件” 不存在,也会触发编译。

【stat指令】

语法:stat [选项] [文件]

功能:查看文件的详细元数据(包括 ACM 时间、大小、权限、inode 等)

常用选项:

  • -c %y [文件]:仅查看文件的内容修改时间(Modify)
  • -c %z [文件]:仅查看文件的属性变更时间(Change)
  • -c %x [文件]:仅查看文件的最近访问时间(Access)
  • 无选项:查看文件的完整元数据(含所有时间、权限、inode 等)

【示例1】:目标文件最近修改时间比依赖文件最近修改时间新

这个时候不会触发编译,因为test是最新的

【示例2】:目标文件最近修改时间比依赖文件最近修改时间旧

从图中可以看到重新进行编译了

【注意】:我们比较的是Modify时间,也就是文件内容最近修改的时间

🔍四、伪目标与项目清理

在开发中,我们常需要 “清理编译生成的中间文件”,这就需要用到伪目标(用.PHONY修饰)。伪目标的特性是 “总是被执行”,不会受文件修改时间的影响。

clean规则为例:

.PHONY: clean
clean:rm -f hello.i hello.s hello.o hello

执行make clean时,无论这些文件是否存在,都会执行rm命令清理它们,方便我们重新编译项目。

🚧五、特殊符号

在 Makefile 中,$@ 和 $^ 是自动变量,用于简化命令书写,分别代表不同的含义:

  • $@:表示当前规则中的目标文件(即规则中 : 左边的文件名)。
  • $^:表示当前规则中的所有依赖文件(即规则中 : 右边的所有文件名,去重后的值)。

📋六、依赖关系缺失问题

缺少test.s生成方式:

make后说没有规则可制作目标“test.s”,该目标是“test.o”所需要的,这个时候就会编译失败

🔗七、如何在使用make后不显示依赖方法

在所有依赖方法前加上@符号后,再次make就会发现依赖方式不回显了

📌八、make工作原理总结

make是如何工作的,在默认的方式下,也就是我们只输入make命令。
  1. make会在当前目录下找名字叫“Makefile”“makefile”的文件。
  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“hello”这个文件 ,并把这个文件作为最终的目标文件。
  3.  如果hello文件不存在,或是hello所依赖的后面的hello.o文件的文件修改时间要比hello这个文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成hello这个文件。
  4. 如果hello所依赖的hello.o文件不存在,那么make会在当前文件中找目标为hello.o文件的依赖性,如果找到则再根据那一个规则生成hello.o文件。(这有点像一个堆栈的过程)
  5. 当然,你的C文件和H文件是存在的啦,于是make会生成 hello.o 文件,然后再用 hello.o 文件声明make的终极任务,也就是执行文件hello了。
  6.  这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
  7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
  8.  make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦

上述就是makefile工具的基础使用,感谢大家的观看!!!

 

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

相关文章:

  • 六安市城乡建设网站沧州百姓网免费发布信息网
  • 俱乐部网站php源码网站构建的工作
  • 【AI论文】机器人学习:教程
  • 普宁网站建设django做网站和js做网站
  • 物联网共享棋牌室:无人值守与24H营业下的轻量化运营实战!
  • Go Web 编程快速入门 07.3 - 模板(3):Action、函数与管道
  • 专业的培训行业网站制作北京网站建设一条龙
  • Spring Bean定义继承:配置复用的高效技巧
  • 湖北网站建设专家本地搭建linux服务器做网站
  • 龙华建网站百度账号官网
  • Python高效爬虫:使用twisted构建异步网络爬虫详解
  • 做爰片的网站公司企业网络宣传设计方案
  • 基于鸿蒙UniProton的PLC控制系统开发指南
  • 建设部网站查询造价师证件地方门户网站的前途
  • 【案例实战】HarmonyOS SDK新体验:利用近场能力打造无缝的跨设备文件传输功能
  • AI边缘设备时钟设计突围:从ppm级稳定到EMC优化的全链路实践
  • typescript—元组类型介绍
  • 限元方法进行电磁-热耦合模拟
  • 三维网站搭建教程直播网站app开发
  • 品牌网站建设 优帮云在百度上做个网站多少合适
  • 无聊。切个水题。
  • 公司微信网站制作wordpress插件汉化教程视频
  • 海东营销网站建设公司福州seo关键词
  • 松江 企业网站建设怎么样做移动油光文字网站
  • 无法生成dump——MiniDumpWriteDump 阻塞原因分析
  • 如何在1v1一对一视频直播交友APP中实现防录屏防截屏功能?
  • 网站做新闻外链有作用吗营销导向的网站建设的主要流程
  • C++笔记(面向对象)对于对象返回方式的讲解
  • CMP(类ClouderaCDP7.3(404次编译) )完全支持华为鲲鹏Aarch64(ARM)POC报告
  • 网站后台管理系统破解网站建设目标规划