• linux下自动构建工具make:makefile



    什么是makefile?大多数人都应该是不太清楚的,因为现在人们基本都用着非常好的适合自己的IDE,而IDE为人们做了makefile该做的,从而导致大多数人并不了解makefile。如果是在Linux下编译程序,那么makefile是必须要掌握的!

    很多linux新手经常是直接用gcc/g++命令来编译程序的,因为对于linux新手,他们的源文件数目少得可怜,他们仅仅用gcc/g++也是可以的,但通常一个项目是拥有非常多的源文件的,而这些源文件直接也有着复杂的关系(编译的先后顺序等),如果此时仍然用gcc/g++命令来直接编译的话,那将会是一个极其痛苦的事情。

    make/makefile介绍

    make是一条命令,makefile是一个文件。

    执行make命令时,makefile会告诉make命令以什么样的规则来编译程序。

    而makfile文件里的内容(也就是编译规则),是需要我们自己来写的!

    来一个简单的例子:

    image-20221120203333125

    这里有四个文件:makefile、add.h、add.c、main.c

    makefile里编写了编译add.c、main.c的规则

    接下来,我们只需要执行一条命令make,即可完成makefile里的编译规则。

    image-20221120203538207

    现在我们再回想一下,如果不用make/makefile的话,我们是如何编译这两个源文件的呢?

    我们应该是用gcc -o main main.c add.c 这一条命令来编译的。如果我们想要编译十次,我们就需要输入十次这样的命令,但如果有了make/makefile,我们只需要十次make。如果来一百个源文件,并且编译十次,我们直接用gcc会极其的麻烦,但是make仍然只需要十次就ok。

    看到这里,想必大家已经认识到了make/makefile的重要性!

    makefile的核心规则

    target ...:prerequisites ...
    	command
    	...
    	...
    
    • 1
    • 2
    • 3
    • 4

    target是一个目标文件,prerequisites是生成target所需要的文件,commmand是make所需要执行的命令(shell命令)。

    而这就是一种依赖关系:target依赖于prerequisites,而生成target的规则(命令)定义在command中。

    值得注意的是:如果prerequisites中如果存在一个文件的时间要比target新,则command才能够执行。

    看下面例子:

    image-20221120205059317

    当main已存在,并且main比main.c、add.c时间都要新的话,makefile中的command是无效的。

    那么我们如何证实呢?

    截屏2022-11-20 20.55.04

    可以看到,main的modify时间是要比main.c、add.c的modify时间要新的,然后执行make的时候出现提示。

    那么我们现在改一下main.c的modify时间(需要对main.c里的文本内容作修改),看看会发生什么。

    截屏2022-11-20 21.00.16

    我们打开文件,在里面添加了若干行空格,就改变了main.c的modify时间,导致main.c的modify时间比main的要新,所以后续执行make命令时能够执行成功。

    这里有一个疑问,那就是要比较target和prerequisites的日期新旧,为什么只比较modify时间?

    因为modify时间只有修改了文件里的内容时,才会跟着改变。

    makefile的寻找规则

    执行make时,会默认执行makefile里的第一个target。当第一个target成功生成(执行)之后,则停止下面的规则。如果当生成第一个target时发现所需的依赖文件不存在,则按从上到下的顺序依次执行规则直到找到依赖文件使得第一个target生成成功。

    image-20221120220738353

    直接执行make时,会为了makefile里的第一个target而从上往下寻找依赖文件。那么如果我们不想生成第一个target呢?假设我们这里只想生成add.o,该怎么办?这时我们需要make加上我们要生成(执行的)那个target。

    image-20221120221217078

    看上图,我们只想生成main.o,所以我们make main.o,而main.o的依赖文件是不存在的,所以向下寻找,直到生成main.o停止,所以也并没有执行makefile里面的add.o add.s add.i等操作。

    makefile的伪目标

    上面我们说过target和prerequisites会根据modify的时间新旧来决定是否执行command。

    那么为什么要这样做呢?

    这是因为,根据prerequisites而生成的target没必要再次编译生成,并且大型项目编译的时间是很长的,只有当prerequisites发生变化时target才需要再次编译生成最新的。

    那么如果我们就是想要每次重新编译生成target而不受时间新旧的约束,这时该怎么做呢?我们可以给target前面修饰一个.PHONY,经过.PHONY修饰的名词就变为来伪目标,该目标下的command每次都可以执行而不受时间约束。

  • 相关阅读:
    实验篇(7.2) 09. 通过安全隧道走对方宽带上网 (FortiClient-IPsec) ❀ 远程访问
    spring是如何解决循环依赖的?
    4.超链接
    数据库精简笔记
    Java import 详解
    STM32速成笔记—SPI通信
    阿里大牛亲自教学分享,最新发布 Spring Cloud Alibaba 笔记
    WEB前端常规技术面试题之HTML+CSS基础
    网安学习Day14(web漏洞-SQL注入类型及提交注入)
    二手车交易管理系统
  • 原文地址:https://blog.csdn.net/qq_67569905/article/details/127955528