Linux | 项目自动化构建工具 - make/Makefile -2

简介: Linux | 项目自动化构建工具 - make/Makefile

四、多学一招:项目清理

1、演示与原理讲解

平时我们在进行各种操作之后目录中都会出现很多文件,此时当我们不想要这些文件的时候,就得去一一删除,显得尤为麻烦,如果编译可以使用Makefile来自动化构建,那清理项目中的文件可不可以呢,我们来看看

  • 此时我们在Makefile中增加一个【清理】功能

image.png

  • 来看一下是否可以达到清理的目的

image.png

  • 当我想使用清理功能的时候,并没有像自动化编译那样直接make,而是在make后面加上了一个clean,这是为什么呢?
  • 新加上的.PHONY是什么?它对clean而言意味着什么?

我们带着这些问题一起进入【伪目标】的学习:book:

2、.PHONY伪目标的作用

  • PHONY是一个伪目标,Makefile中将.PHONY放在一个目标前就是指明这个目标是伪文件目标。其作用就是防止在Makefile中定义的执行命令的目标和工作目录下的实际文件出现名字冲突
  • 也就是下面这句,此时的clean被.PHONY修饰了,那么它就可以反复执行它的依赖方法
.PHONY:clean
  • 可以看到对于目标文件clean来说,它的依赖文件列表为空,上面我们也有提到过它可以为空
 11 clean:
 12     rm -f test.o test.s test.i

所以只要你一直使用【make clean】,它便会反复地执行rm -f test.o test.s test.i

  • .PHONY配置项的目标clean并不是其他文件生成的实际文件,使make命令会自动绕过隐含规则搜索过程,也就是说执行命令make clean自动忽略名为"clean"文件的存在,因此声明.PHONY配置项会改善性能,并且不需要担心实际同名文件存在与否😮
  • 【通俗一点说】:.PHONY修饰的目标clean并不是某个依赖项生成的实际文件,因此make命令不再去搜寻当前文件夹下是否有clean文件,这样少去做一些事,自然会改善性能,并且不用担心当前文件夹下是否有同名的文件

我们到命令行中来验证一下:keyboard:

image.png

  • 可以看到,我进行了三次make clean,不过其实在第一次执行的时候,就已经达成了我们清理的目的,可是后面还可以继续执行,这其实就是.PHONY修饰起的作用
  • 其实对于【clean】来说,不加修饰其实也是可以辺反复执行的,这点我们在本模块开头的时候有说到过。我现在将这个修饰去掉,来试试看

image.pngimage.png

  • 可以看到,即使是去掉了.PHONY做修饰之后一样是可以反复执行

那就有同学问:这是为什么呢?为何clean不加.PHONY修饰也可以多次执行

  • 原因就在于它的依赖对象为空,当我们需要生成这个【clean】目标文件的时候就不需一些文件必须要存在,因此就可以一直[clean]

3、.PHONY伪目标的原理

  • 可是呢,对于其他的指令就不行了,例如我们上面说到过的gcc去编译一个文件的过程

image.png

  • 我们试着在【mytest】前面加上一个.PHONY的修饰试试

image.png

  • 然后再去试试能不能进行反复使用【这里给读者详细解释一下.PHONY修饰的原理】
  • 我们来详细分析一下,首先可以清楚的是加上.PHONY修饰之后便可以多次make,但是可以看到在编译的过程中进行make的时候所执行的指令不太相同,只有gcc test.o -o mytest这一句,却少了如何产生【test.o】的过程,这是为何呢❓
  • 因为在经过一次make之后,gcc对【test.c】进行了预编译、编译、汇编,最后生成了【test.o】,那它就已经在那里了,在此中间我们没有再对源文件进行再度修改,在编译的时候,其实会去查看目标对象和依赖对象的生成时间,若是依赖对象的生成时间要早于目标对象,说明它还没有被重新修改过,所以无需再度去重新编译生成(这一块在后面make的工作原理中细讲)
  • 因此我们再去make的话gcc是不会重新编译的,可以当我去修改了一下【test.c】这个源文件之后,再度去make一下的话gcc又会对这个源文件进行一个重新的全过程编译。 ❗编译这一块比较复杂,需要重点理解❗

image.png

  • 不过其实可以看出,每次去修改一下就重新编译全部的文件,也是挺繁琐的。所以我们在开发的时候一般不给编译生成的目标文件带.PHONY的修饰,就防止其被多次重复编译

【总结一下】:

📚 .PHONY修饰的是伪目标,对于伪目标来说,它可以被反复执行

📚 .PHONY修饰的一定能被反复执行,但是能被反复执行的不一定被.PHONY修饰

以上就是有关伪目标的叙述,如果还不太清楚可以看看这篇文章 ——> 链接

五、make的工作原理分析

1、再谈make与Makefile

  • 通过【ldd】去查看make指令的动态依赖关系,我们可以发现make指令也是依赖于标准的C库,而我们在Makefile中写得也都是一些指令,因此使用make指令才可以对Makefile中的内容做一个识别

image.png因此我们可以得出一个结论

👉make是专门给【Makefile】写的一个命令,在执行make的时候,就会自动在你当前目录下去搜索Makefile这个文件,搜索之后打开,然后对它里面的内容做分析

那make是如何进行分析Makefile的呢,有什么规则吗❓

  • make扫描Makefile文件时会默认执行第一组依赖关系和依赖方法
  • 还记得我们
  • 在获取mytest这个目标对象的时候都是直接使用的【make】吗;
  • 而在获取clean这个目标对象时却用的是【make clean】
  • 那你是否会感到疑惑为何不使用【make mytest】就可以获取到吗,就是因为==默认执行的就是第一组的依赖关系和依赖方法==
  • 我们可以试着把【clean】和【mytest】调个位置

image.png

  • 可以看到,在调换了位置之后我们直接【make】的话获取的就是clean对象了,想要去使用gcc编译源文件生成可执行文件就需要用到【make mytest】。
  • 不过也并不是第一组依赖关系和依赖方法就一定要直接【make】,我们使用【make clean】也是可以用的

2、探究make的判断机制🔍

好,我们来深入探讨一下刚才遗留下的问题:make究竟是如何知道我们的可执行文件是否需要重新编译呢❓

  • 再来回顾一下,当我们执行完一次【make】获取mytest这个目标文件后,第二次再去执行【make】指令就不会其效果了,这是为何呢?

image.png

  • 我们可以将源文件和可执行文件当做是一条时间轴。对于可执行文件来收,它生成的时间一定是晚于源文件的【因为中间要经过一系列编译 + 链接的过程】

image.png

  • 我们可以通过【stat】这个指令来查看源文件和可执行文件的所有属性,不过要观察的还是其中一个叫做ACM时间
  • Access: 最后一次访问该文件的时间
  • Change:最后一次改变该文件属性或状态的时间
  • Modify:最近一次修改文件内容的时间【比较的是这个时间】
  • 可以很清晰地看出20:17:56是要晚于17:45:48的。所以【make】指令才会不起作用。==所以它就是通过这个Modify时间来进行对比才能判断出是否需要重新编译==

image.png

那我们能否钻个空子,来欺骗一下make呢:stuck_out_tongue_winking_eye:

  • 此处我们可以使用这个【touch】指令,它除了创建文件之外还有其他功能
  • 若是要创建的这个文件不存在,那就将其创建出来
  • 若是要创建的这个文件存在,那就修改它的ACM时间为最新的时间

我们来试试看。可以很清楚地看到源文件的Modify时间从17:45:48变到了20:17:56,那就比可执行文件要来得晚了,此时再去【make】的话就会重新编译了

image.png

拓展:VS下可执行文件生成问题

我们在VS下有时候经常会出现修改了源代码但是生成不了.exe可执行文件的问题,既然说到了【源文件】和【可执行文件】的关系,就顺带拓展一下

  • 原因是你在编译的时候可能有的文件的时间被改了,但是可能那个时间的更改要么有BUG,要么VS在识别你的源代码时把它的时间依旧识别成老的源代码时间了,所以不会对源代码进行重新编译(👉is up to date)。
  • 所以形成的新的源代码的.obj文件没有更新,最后再怎么去链接去形成.exe可执行文件都执行不了【清理一下项目的其余文件就可以了,只保留源文件然后重新编译一下】

六、总结与提炼

最后我们来总结一下本文所学习的内容:book:

本文我们学习了Linux下的项目自动化构建工具 - make/Makefile

  • 首先清楚了【Makefile】它是一个文件,我们可以在里面写入一些编译的规则。而【make】则是一个命令,它可以用来解析Makefile中的内容
  • 接着,在通过初次写一个小案例去接触make/Makefile的时候我们了解到了【依赖关系】和【依赖方法】,不仅感性地去理解了它们,而且深入地清楚了它们的底层实现逻辑是基于数据结构中的栈
  • 然后,不仅仅局限于一个目标文件,我们又学了一招,知道了如何去清理项目中的文件,知道了.PHONY修饰的文件叫做【伪目标文件】
  • 最后,我们通过再度触及make/Makefile,真正搞清楚了它们之间的关系,也了解到make在判断一个文件是否需要重新编译的时候是基于比较源文件目标文件的【Modify时间】

以上就是本文要讲解的所有内容,感谢您的观看

相关文章
|
1天前
|
Linux 程序员 计算机视觉
【linux 学习】在Linux中经常用到的cmake、make、make install等命令解析
【linux 学习】在Linux中经常用到的cmake、make、make install等命令解析
13 0
|
1天前
|
Linux Shell C语言
Linux:自动化构建 - make
Linux:自动化构建 - make
13 1
|
1天前
|
Shell Linux 编译器
C语言,Linux,静态库编写方法,makefile与shell脚本的关系。
总结:C语言在Linux上编写静态库时,通常会使用Makefile来管理编译和链接过程,以及Shell脚本来自动化构建任务。Makefile包含了编译规则和链接信息,而Shell脚本可以调用Makefile以及其他构建工具来构建项目。这种组合可以大大简化编译和构建过程,使代码更易于维护和分发。
30 5
|
1天前
|
安全 Linux Python
Volatility3内存取证工具安装及入门在Linux下的安装教程
Volatility3内存取证工具安装及入门在Linux下的安装教程
Volatility3内存取证工具安装及入门在Linux下的安装教程
|
1天前
|
数据可视化 小程序 Linux
【Linux】自动化构建工具make/Makefile和git介绍
【Linux】自动化构建工具make/Makefile和git介绍
15 0
|
1天前
|
Shell Linux 编译器
C语言,Linux,静态库编写方法,makefile与shell脚本的关系。
总结:C语言在Linux上编写静态库时,通常会使用Makefile来管理编译和链接过程,以及Shell脚本来自动化构建任务。Makefile包含了编译规则和链接信息,而Shell脚本可以调用Makefile以及其他构建工具来构建项目。这种组合可以大大简化编译和构建过程,使代码更易于维护和分发。
16 3
|
1天前
|
数据采集 存储 API
网络爬虫与数据采集:使用Python自动化获取网页数据
【4月更文挑战第12天】本文介绍了Python网络爬虫的基础知识,包括网络爬虫概念(请求网页、解析、存储数据和处理异常)和Python常用的爬虫库requests(发送HTTP请求)与BeautifulSoup(解析HTML)。通过基本流程示例展示了如何导入库、发送请求、解析网页、提取数据、存储数据及处理异常。还提到了Python爬虫的实际应用,如获取新闻数据和商品信息。
|
1天前
|
数据采集 机器学习/深度学习 算法框架/工具
利用Python实现基于图像识别的自动化数据采集系统
本文介绍了如何利用Python编程语言结合图像识别技术,构建一个自动化的数据采集系统。通过分析图像内容,实现对特定信息的提取和识别,并将其转化为结构化数据,从而实现高效、准确地采集需要的信息。本文将详细讨论系统的设计思路、技术实现以及应用场景。
|
1天前
|
Web App开发 Python
在ModelScope中,你可以使用Python的浏览器自动化库
在ModelScope中,你可以使用Python的浏览器自动化库
18 2
|
1天前
|
JSON 监控 调度
局域网管理软件的自动化任务调度:Python 中的 APScheduler 库的应用
使用 Python 的 APScheduler 库可简化局域网管理中的自动化任务调度。APScheduler 是一个轻量级定时任务调度库,支持多种触发方式如间隔、时间、日期和 Cron 表达式。示例代码展示了如何创建每 10 秒执行一次的定时任务。在局域网管理场景中,可以利用 APScheduler 定期监控设备状态,当设备离线时自动提交数据到网站,提升管理效率。
24 0

热门文章

最新文章