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

什么是make/Makefile

以往在Linux下写程序,每次改代码,我们都需要进行重新编译,如果是单一文件还好,假如一个工程中的源文件有许多,我们不可能去一个一个文件得使用gcc

所以makefile的功能是自动化编译,一旦编译好,只需要一个make命令,整个工程完全自动编译,极大得提高软件开发效率

下面我们通过一个简单的例子来学习Makefile


make/Makefile的一个简单的例子

要先明白什么是make,什么是Makefile
make是一条指令
Makefile是当前目录下的文件


首先,要在源文件同级目录下建立一个名为makefile/Makefile文件(m是否大小写都可以)

然后在makefile中写入:

mycode:mycode.c
	gcc -o mycode mycode.c

mycode:mycode.c 是依赖关系,意思是mycode依赖于mycode.c文件,将mycode.c编译成mycode
gcc -o mycode mycode.c是依赖方法,光有依赖关系还不够,还要有依赖方法:如何把mycode.c形成mycode
并且要注意:依赖方法前面必须是一个tab
在这里插入图片描述

现在一个最简单的Makefile就写好了,下面运行来试一下
目前目录下没有名为mycode的可执行文件,然后输入命令make,接着ll发现,新增了名为mycode的可执行文件
并且我们还可以看到执行make命令后,会打印出执行的依赖方法gcc -o mycode mycode.c
在这里插入图片描述

make完一次后,再make就不允许了
在这里插入图片描述

所以,以后就不需要再手动进行编译了,配置好makefile文件后,命令行输入make指令,会自动地在当前目录下寻找makefile文件,然后通过里面的依赖关系和依赖方法,执行对应的依赖方法

既要支持编译,也要支持清理,不然如果一个项目中文件过多,一个一个得删除可执行文件也是十分麻烦的

mycode:mycode.c
	gcc -o mycode mycode.c
clean:
	rm -f mycode

这里的clean是自定义的依赖关系,名字随便取,冒号后面为空,表示clean不依赖任何文件,随时都可以执行对应的依赖方法

输入make clean会执行依赖方法
在这里插入图片描述


问题1

我们现在把makefile写得复杂一些

mycode:mycode.o
	gcc -o mycode mycode.o
mycode.o:mycode.s
	gcc -c mycode.s -o mycode.o
mycode.s:mycode.i
	gcc -S mycode.i -o mycode.s
mycode.i:mycode.c
	gcc -E mycode.c -o mycode.i
clean:
	rm -f mycode mycode.o mycode.s mycode.i

然后输入make,我们发现执行得顺序与我们在makefile中的顺序不一样
在这里插入图片描述

原因是:
make指令进行扫描时,优先根据依赖关系,所有依赖关系的文件列表在当前目录下是否存在,若不村在,makefile会类似递归似的形成依赖文件,最后根据依赖文件形成结果文件

  1. mycode依赖mycode.omake发现当前目录下没有mycode.o文件,然后mycode.o有自己的依赖关系,依赖mycode.s文件
  2. 但是当前目录下没有mycode.s文件,mycode.s有自己的依赖关系,它依赖于mycode.i
  3. 但是当前目录下没有mycode.i文件,mycode.i有自己的依赖关系,它依赖于mycode.c
  4. mycode.c是有的,然后mycode.c生成mycode.imycode.i生成mycode.smycode.s生成mycode.o,最后mycode.o变为mycode,得到最终的目标文件

这个过程类似于栈和递归

所以在makefile中,是乱序也不影响


问题2

前面在使用下面这个makefile文件时,为什么输入make会执行mycode:mycode.c这个依赖关系和其对应的依赖方法,而想要清理就需要输入make clean命令?

是因为make会自顶向下扫描makefile,将第一个依赖关系的目标文件充当make的默认动作

其实输入make mycode也会达到和make相同的效果
在这里插入图片描述

下面将clean和mycode调换一下位置;

clean:
	rm -f mycode mycode.o mycode.s mycode.i
mycode:mycode.o
	gcc -o mycode mycode.o
mycode.o:mycode.s
	gcc -c mycode.s -o mycode.o
mycode.s:mycode.i
	gcc -S mycode.i -o mycode.s
mycode.i:mycode.c
	gcc -E mycode.c -o mycode.i

那么make就默认执行清理任务,想生成mycode就需要手动输入make mycode
在这里插入图片描述


问题3

前面我们可以知道,make一次后,不能够进行第二次make,是为什么呢?

原因:一个源文件被make一次后,如果源文件没有被修改,make是不允许重新编译的
目的:主要是为了提高编译效率

是如何做到的呢?

先有源文件,后又对应的可执行文件,所以一般而言,源文件的最近修改时间是一定要老于可执行文件的最近修改时间
如果修改了源文件,目前还有上一版本源文件生成的可执行文件
所以此时,源文件的最近修改时间就新于可执行文件的时间
所以只需要对比可执行文件和源文件的最近修改时间

如果可执行文件新于源文件,不需要重新编译
如果源文件新于可执行文件,需要重新编译
一般而言,这两个文件的最近修改时间是不会相同的
这里对于时间的比较,比较的是时间戳

下面可以验证一下:

stat命令可以查看文件修改时间
在这里插入图片描述
这里会显示三个时间:Access,Modify,Change
Access是访问时间
Modify是对文件内容修改时间
Change是对文件属性修改时间

执行touch + 一个已经存在的文件,会将3个时间都修改,加上选项-a,-m,-c是修改单个时间

下面我们来验证一下:
make一次,再make一次,发现不允许make
接着修改mycode.c的时间,再make一次,发现就被允许了
在这里插入图片描述

但是如果想每次的make都被允许,不管源文件和可执行文件的时间。可以使用.PHONY

.PHONY:mycode
mycode:mycode.o
	gcc -o mycode mycode.o
mycode.o:mycode.s
	gcc -c mycode.s -o mycode.o
mycode.s:mycode.i
	gcc -S mycode.i -o mycode.s
mycode.i:mycode.c
	gcc -E mycode.c -o mycode.i
clean:
	rm -f mycode mycode.o mycode.s mycode.i

.PHONY是伪目标,用它修饰mycode,就会让mycode的依赖方法总是要重新编译

单一一般不建议这么用,不建议把目标文件用伪目标修饰
一般建议用.PHONY修饰清理:

mycode:mycode.c
	gcc -o mycode mycode.c
.PHONY:clean
clean:
	rm -f mycode

特殊符号

$@,替代依赖关系中,冒号左侧的内容
$^,替代依赖关系中,冒号右侧的内容

mycode:mycode.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f mycode

每次执行依赖方法后,都会将依赖方法打印到屏幕上,如果不想要打印,可以在依赖方法前加@

mycode:mycode.c
	@gcc -o $@ $^
.PHONY:clean
clean:
	@rm -f mycode

执行makemake clean后,什么都没有打印:
在这里插入图片描述

  • 25
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯癫了的狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值