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

【Linux】自动化构建工具--make/Makefile

欢迎拜访:Madison-No7个人主页
文章主题:自动化构建工具--make/Makefile
隶属专栏:从0到1掌握Linux
写作日期2025年10月24号

目录

前言:

一、什么是make和makefile

makefile带来的好处:

使用make和makefile:

依赖关系:

依赖方法:

二、make的工作原理

2.1 make的自动化推导过程:

2.2 项目清理

2.3 .PHONY伪目标:

2.4 源文件的重新编译:

2.5 makefile的相关语法:

2.5.1 makefile对单文件的编译:

2.5.2 makefile对多文件的编译:


前言:

在一个大型的项目中,源文件不计其数,如果我们手动使用gcc/g++去编译源代码,那将会变得十分麻烦,而且容易出错。所以在Linux中有专门的自动化构建工具---make/makefile,来解决多个源文件编译的问题。

一、什么是make和makefile

⼀个⼯程中的源⽂件不计数,其按类型、功能、模块分别放在若⼲个⽬录中,makefile定义了⼀系列的规则来指定,哪些⽂件需要先编译,哪些⽂件需要后编译,哪些⽂件需要重新编译,甚⾄于进⾏更复杂的功能操作。make是一个命令行工具,运行时会读取当前目录的 makefile,根据规则自动执行编译、链接等命令.。

📖简单来说,make是⼀条命令,makefile是⼀个⽂件,两个搭配使⽤,完成项⽬⾃动化构建

makefile带来的好处:

“⾃动化编译”,⼀旦写好,只需要⼀个make命令,整个⼯程完全⾃动编译,极⼤的提⾼了软件开发的效率。

使用make和makefile:

1.创建makefile文件并进行文本编辑:

makefile中的m大小写都可以。

2.定义依赖关系和依赖方法:

3.执行make命令:

依赖关系:

test:test.c     #:左边表示的是目标文件,:右边表示目标文件所依赖的文件列表。

依赖关系是指一个事物的存在或运行必须以另一个事物为前提,比如test可执行文件依赖test.c源文件,因为必须通过test.c翻译才能生成可执行文件。


依赖方法:

        gcc -o test test.c

依赖方法是指当存在依赖关系时,如何按顺序、按规则处理这些依赖,先确保test.c存在,再执行程序的翻译过程。

💡 依赖关系和依赖方法在生活中的例子:

比如你今天要做一份宫保鸡丁:

  • 依赖关系:宫保鸡丁依赖 “炒好的鸡丁”“炒好的花生”“切好的黄瓜丁”;“炒好的鸡丁” 依赖 “切好的鸡丁” 和 “调好的料汁”;“切好的鸡丁” 依赖 “完整的鸡胸肉” 和 “菜刀”。这是一条依赖链。
  • 依赖方法:先处理最底层依赖(用菜刀把鸡胸肉切成丁),再处理中间依赖(用切好的鸡丁和料汁炒鸡丁),最后处理最终依赖(把炒好的鸡丁、花生、黄瓜丁混合翻炒,做出宫保鸡丁)。

对应的makefile就是:

宫保鸡丁: 炒鸡丁 炒花生 切黄瓜丁把所有食材混合翻炒出锅炒鸡丁: 切鸡丁 料汁用鸡丁和料汁翻炒切鸡丁: 鸡胸肉 菜刀用菜刀把鸡胸肉切丁

二、make的工作原理

2.1 make的自动化推导过程:

观察上图可以发现,执行make指令时,实际运行的命令顺序与makefile中的编写顺序相反。这种反向执行机制源于文件间的依赖关系:要生成test需要test.o,但该文件不存在;而makefile中提供了生成test.o的方法,不过这又需要先有test.s文件。同样地,生成test.s又依赖于test.i文件。因此,完整的构建流程必须从test.i开始,依次生成test.s、test.o,最终才能得到test目标文件。这种依赖关系实质上构成了一个栈式结构,决定了命令的执行顺序与编写顺序相反的特性。

🌟注意:

由于是自动化推导,makefile文件中的依赖方法可以是任意顺序,但是不能缺少。还可以这样:

上面只是为例演示make的自动化推导过程,平时我们编译源文件不会这样定义。

2.2 项目清理

我们有时候需要清理文件,如果使用rm +要清理的文件名,如果要清理很多的文件,难道我们每次都要自己手动敲一遍吗?那就太麻烦了,同样可以使用自动化工具make与makefile,帮助我们清理。

同样需要定义依赖关系和依赖方法,清理文件这个操作,不需要依赖任何其他文件,所以:右边的依赖关系什么也没写,直接执行对应的操作,也就是执行依赖方法,依赖方法可以自己指定删除哪些文件。clean是自己命名的,表示清理的意思,大家也可以根据自己的喜好,取其他的名字。有了上面的依赖关系和依赖方法,此时只需要在命令行中执行make clean指令,就可以把自己指定要删除的文件删除。

📖为什么删除时make后面要加clean?

因为make会自顶向下扫描makefile,单独的make指令,会默认执行第一个依赖方法。

2.3 .PHONY伪目标:

.PHONY用于声明 “伪目标”(Phony Target)。这些目标不是实际的文件,而是代表一组命令(比如清理文件、编译全部、运行程序等)。如果要想让makefile文件中对应的依赖方法总是被执行,可以用.PHONY对相应的标签进行修饰。

比如:

.PHONY:clean                                                                                                                                                                            
clean:rm -rf test.i test.s test.o test

📖总是被执行意思:

强制让目标被执行,即使该目录下存在同名文件。如果目录中没有与目标重名的文件,即使不加.PHONY,make clean 也会每次都执行对应的命令.

test目标文件没有被.PHONY修饰,只能执行一次test对应的gcc命令。

📖为什么不能连续编译源文件:

如下图,当执行完一次make,对源代码编译后,再去执行make,就不会对源代码重新编译。

对于一个源代码,进行一次编译,得到一个可执行文件后,如果没有对源代码做任何修改,再去对源代码进行编译,make会觉得没必要,不会重新编译,另外如果有1000个源文件需要编译,而我们只对其中的几个做了修改,编译器只对修改了的源文件重新编译,而对没改的源文件,编译器不做处理,这也是为了提升编译的效率。而加上.PHONY修饰test,make可以执行无数次,也就是强制make执行编译,即使该目录下存在test可执行文件了,但是这样是没有必要的。

 🌟 结论:

一般情况下,对编译操作不加.PHONY进行修饰,而是对清理操作加.PHONY修饰,因为在该目录下当有很多文件时,如果刚好有个clean文件与makefile中的clean目标文件同名了,make会认为 “目标已完成”,不会执行 rm命令,导致清理失败,加上.PHONY修饰,就会无视同名。

2.4 源文件的重新编译:

📖make在什么情况下,才会对源文件重新编译呢?(除开加.PHONY修饰)

执行make命令,自动生成一个可执行文件,如果还想对源文件编译就不行了,因为没有对源代码做任何修改,去对源代码进行编译,编译所生成的可执行文件与之前所生成的也一样,make会觉得没必要,不会重新编译。所以只有修改了源文件的内容,make命令所生成的可执行文件才与之前的不一样。

📖那编译器怎么知道源文件的内容修改了呢?

在Linux下,一切皆文件,文件=内容+属性,而与文件相关联的时间有三个,简记为ACM,A(Access)、C(Change)、M(Modify)。而Modify的时间与文件的内容修改有关,Change时间与文件的属性修改有关。也就是说Modify的时间改变了,就说明文件的内容改变了,就可以对源文件重新编译了;

📖查看文件时间:

stat test:查看mytest文件的有关时间。

  • Access:常指的是⽂件最近⼀次被访问的时间。
  • Modify: 内容变更,Modify时间更新。
  • Change:属性变更,Change时间更新。

这三个时间是相互关联的,有的操作可能会同时更新多个时间。

⏳ 修改文件的内容后,查看文件的有关时间:

修改文件的内容,这三个时间都会更新,因为修改文件内容,首先要访问该文件,其次修改后,文件的大小(属于文件属性)会发生变化,所以这三个时间都会更新。

⏳ 单纯的修改文件属性,只有Change时间会变化。

⏳ 单纯的访问文件:

在 Linux 的早期版本中,每当文件被访问时,其Access 时间都会立即更新;这些时间信息都存储在计算机的硬盘上,而硬盘都属于外部设备,进行读写操作会比较慢,过高频率的更新一个文件的Access,当整个系统在被多个用户使用的时候,就会有大量的Access更新行为,这些行为都会往硬盘中写数据,这就会导致整个系统的运行速度下降。而当前的 Linux 版本,通过策略优化:仅在两种场景下更新 Access:

  • 文件的修改(Modify)时间或状态变更(Change)时间,晚于当前 Access 时,与Access时间间隔还需超过 24 小时;
  • 距离上次 Access 更新已超过 24 小时。

📖手动更新文件时间:

  • touch test.c:将test.c文件的所有时间更至最新。
  • touch -m test.c:将test.c文件的Modify时间更至最新。
  • touch -a test.c:将test.c文件的Access时间更至最新。
  • touch -c test.c:将test.c文件的Change时间更至最新。
     

🌟 总结:

如果要对一个已经编译的源文件重新编译,就需要改变源文件的内容,也就是改变源文件的Modify Time,查看源文件的相关时间用stat指令,改变源文件的Modify时间,可以修改源文件的内容,还可以使用touch指令,手动修改,还可以在makefile中对目标文件加.PHONY修饰。

2.5 makefile的相关语法:

2.5.1 makefile对单文件的编译:

执行make后,test因为有.PHONY修饰,所以无论是否存在同名文件,都会执行对应命令。test目标下的echo $(BIN)会将BIN替换为code,执行echo code后输出code。

如果不想把echo $(BIN)命令在make执行的时候回显出来,可以在命令前加@符号。

📖初始版本的makefile写法:

📖特殊变量:

  • $@:代表⽬标⽂件名。
  • $^: 代表依赖⽂件列表

更优雅的写法:

  • %.o:%.c   :%.c 展开当前⽬录下所有的.c。%.o: 同时展开同名.o

  • %<: 对展开的依赖.c⽂件,⼀个⼀个的交给gcc

我们对多文件编译的时候,有一个习惯,喜欢把.c文件先编译成.o文件,再通过链接生成可执行文件,所以%.o:%.c是为了应对多文件编译引入,$<也是为了对多文件的编译引入,<符号它的指向就像.o < .c,就是把.c文件编译成.o文件。

2.5.2 makefile对多文件的编译:

📖makefile模板:

如果有很多的源文件需要编译,不可能打出所有的.c源文件,makefile高级的地方就体现在makefile有自己的wildcard函数,可以获取当前目录下的所有.c文件。


完。

今天的分享就到这里,感谢各位大佬的关注,大家互相学习,共同进步呀!

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

相关文章:

  • 乡镇网站建设工作计划商城网站支付端怎么做
  • 咸阳网站开发公司电话seo网站关键词排名优化公司
  • 八股文面试题(全栈所有)
  • Mac Studio 和 DGX Spark 可用性分析
  • 【小白笔记】「while」在程序语言中的角色
  • 网站推广员怎么做怎么投诉网站制作公司
  • Flexbox 与定位结合-实现更复杂布局
  • 基于随机森林算法的Boss直聘数据分析及可视化-hadoop+django+spider
  • 最适合seo的网站源码专门做网页的网站
  • 企业微信机器人配置webhook自动推送错误订单信息
  • Web3 前端与合约交互
  • 基于window/ubuntu安装rknn-toolkit2【docker】
  • Mac安装配置MySQL
  • JumpServer堡垒机的安装部署
  • Harmony鸿蒙开发0基础入门到精通Day05--JavaScript篇
  • 福州医疗网站建设电商平台管理系统
  • 【乐鑫】乐鑫平台库文件生成方法
  • 文件IO操作
  • GStreamer视频编码
  • 【Go】--闭包
  • 正规网店代运营公司seo难不难
  • 【Dataset】如何高效处理海量数据并从中智能筛选出有代表性的样本?
  • 攻防世界-Web-Confusion1
  • python:怎样用 Django 开发电子商务程序
  • 【u-boot】u-boot驱动模型-struct uclass_driver
  • 昌吉网站建设公司怎么用php安装wordpress
  • 山西网站建设营销什么价格html模板在哪找
  • MATLAB 实现基于短时傅里叶变换 (STFT) 的音频信号时频分析与可视化
  • 第十章-Tomcat性能测试与实战案例
  • 1.Linux初识