目录
前言
一、是什么?
二、怎么样的?
三、原理及细节
图解代码
细节1:make工作规则
①依赖文件存在
②依赖文件不存在
③依赖文件列表为空(特殊)
.PHONY关键字
细节2:makefile识别程序需要重新编译?
四、常用makefile写法
①内置符号法
② 变量替换法
前言
前面在认识gcc/g++中我们知道,编译代码并形成可执行程序的指令为:gcc xxx.c -o xxx 。但是呢这样对于少量源文件来说还好,可是对于一个真正的工程项目,源文件是不计其数的,一个一个的编译未免有些许麻烦,有没有什么更加快速的方法呢?肯定有,不然我也不会写这篇文章的,对吧?来看看今天的主角make与makefile,用完你会爱上的!!
一、是什么?
- make就是单纯的一个命令,是一个解释makefile中指令的命令工具。。
- makefile就是一个单纯的文件,但是内容一旦写好,只需要make命令,整个工程完全自动化编译,可以大大提高开发的效率!!
- make和makefile搭配使用以完成项目的自动化构建。。
二、怎么样的?
看看实例代码:
先创建一个简单的C代码如下:
建一个简单makefile文件,如下
完成编译工作
可以看到,只需要一个make命令就能完成编译工作并形成可执行程序。。这就不需要每次编译源文件的时候都输入gcc xxx.c -o xxx这样一长串指令,效率提高了很多!
完成清理工作
可见,make会根据makefile的内容,完成编译/清理操作!!十分的nice!
大家估计会有疑问为什么编译工作仅仅用make一条命令,而清理用make clean?接着往下看!
三、原理及细节
图解代码
- 依赖文件列表
①可以同时存在多个源文件,以空格为分隔符,如:test.c test1.c .......
②还可以为空,比如下面的清理操作,clean:,这是一种特殊的依赖关系!
- 依赖关系
目标文件的形成依赖于后面文件列表,这就构成了依赖关系。如上述的test.exe:test.c,clean: 。(特殊)
- 依赖方法
目标文件形成的所依赖的方法,也就是光有依赖关系还不够,还得需要对应的方法才能实现。。如上述的gcc以及rm操作就是依赖方法。。
此时上述的过程可以这样理解,使用make命令时,会在当前目录下寻找makefile文件,读取里面的内容,并根据依赖关系去找到对应的依赖方法并执行生成对应的目标文件!!
细节1:make工作规则
默认情况下,单单使用make命令是从上往下读取文件的, 默认执行第一对依赖关系和依赖方法,其他的不管,形成的是第一个目标文件!
①依赖文件存在
先看演示:
当前目录下的文件:
makefile文件内容:
make一下看结果:
会发现此时执行顺序是从下往上的,不是说仅仅使用make命令时,从上往下读,只会执行第一对依赖关系吗?
是的没错,还是从上往下读,执行第一对依赖关系,但是因为第一对依赖关系中的依赖文件test.o并不存在于当前目录,那么此时make会在当前文件中找目标文件为test.o的依赖关系,发现依赖文件test.s也并不存在,以此类推,最后推导发现依赖文件test.c存在,就执行对应的依赖方法,在从下往上。如果推导至最后发现还是没有文件,那么此时的make就会直接退出,并报错!!
②依赖文件不存在
注意:这种情况下的不存在不是为空哦
演示:
当前目录下的文件:
makefile中的内容:
code.c文件并不在该目录下,来看结果:
可见,当依赖文件不存在时,make就不工作了!!!!!
③依赖文件列表为空(特殊)
看演示:
将上述的clean操作放在test.exe前面
看结果:
从上往下读取,但是碰到依赖文件为空时,会直接执行对应的依赖方法。。不会再向下推导了。。也就是make将这种情况也视为依赖文件存在的情况。。
那么此时如果要执行生成其他的目标文件,那就需要带上对应目标文件的名称!
所以,我们一般习惯上把形成可执行程序的目标文件放在第一位,文件的清理工作放在其他的位置,这也是开头演示时为什么使用make clean命令的原因!
小总结: make会自动根据文件的依赖性,进行自动推导,帮助我们执行所有相关的依赖方法!!
.PHONY关键字
.PHONY:xxx
xxx对应的依赖方法,总是要被执行的!!!!
来看对比:
无该关键字时:
可以看到,只能make一下,当你连续make多次,是无法实现的!!因为makefile对最新生成的可执行程序,默认不会在重新生成,这样可以提高编译的效率!!除非你更新可执行程序所依赖的源文件时,才可以重新make!
但是可以加上.PHONY关键字就能打破这种限制!
如下图:
结果:
但是实际上对于生成可执行程序的,一般不用这个关键字去修饰,这样编译效率不高(对于一个大工程而言),默认情况都是用于修饰clean这样的项目清理文件。。让清理工作总是被执行!
细节2:makefile识别程序需要重新编译?
实际上就是对比源代码和可执行程序最近一次形成或修改时间,谁是最新的。
- 如果源文件是最新的,说明刚完成更改,需重新编译!!允许make!
- 可执行程序是最新,说明不需要重新编译,不允许make!!
先有的源文件,编译才能形成可执行程序!所以源文件和可执行程序形成和修改的时间一定不一样,除非特意修改!!
这就是为什么不能连续make的原因!!
但是有一点要注意:
对于那些没有依赖文件的目标文件,就没有这种限制!!比如上述的clean清理工作,它就可以无限make,爱咋咋地!
四、常用makefile写法
对于上面的依赖方法的写法还是有点麻烦,还是要写gcc xxx.c -o xxx。(小文件还行)来看以下两种写法。
①内置符号法
$^:代表依赖文件
$@:代表目标文件
执行结果也是一样:
注意:对于清理文件不能用内置符号。
② 变量替换法
执行结果:
这东西和宏类似,只需要改变上面变量的值就可以了,很方便!!
补充:
每次我们在make时,都会有gcc……这条指令显示出来,如果不想显示,可以这样改
在依赖方法前加上@符号即可。
好了,兄弟们,今天的分享就到这里,如果觉得对你有所帮助,欢迎点赞+关注+收藏!!