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

目录

什么是make/Makefile

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

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

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


make/Makefile的一个简单的例子

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

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

然后在makefile中写入:

bash 复制代码
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文件,然后通过里面的依赖关系和依赖方法,执行对应的依赖方法

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

bash 复制代码
mycode:mycode.c
	gcc -o mycode mycode.c
clean:
	rm -f mycode

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

输入make clean会执行依赖方法


问题1

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

bash 复制代码
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调换一下位置;

bash 复制代码
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

bash 复制代码
.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修饰清理:

bash 复制代码
mycode:mycode.c
	gcc -o mycode mycode.c
.PHONY:clean
clean:
	rm -f mycode

特殊符号

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

bash 复制代码
mycode:mycode.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f mycode

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

bash 复制代码
mycode:mycode.c
	@gcc -o $@ $^
.PHONY:clean
clean:
	@rm -f mycode

执行makemake clean后,什么都没有打印:

相关推荐
matlab的学徒12 分钟前
Web与Nginx网站服务(改)
linux·运维·前端·nginx·tomcat
Insist75317 分钟前
prometheus安装部署与alertmanager邮箱告警
linux·运维·grafana·prometheus
BAGAE1 小时前
MODBUS 通信协议详细介绍
linux·嵌入式硬件·物联网·硬件架构·iot·嵌入式实时数据库·rtdbs
灿烂阳光g1 小时前
SELinux 策略文件编写
android·linux
xqlily1 小时前
Linux操作系统之Ubuntu
linux·运维·ubuntu
阿部多瑞 ABU1 小时前
《基于国产Linux的机房终端安全重构方案》
linux·安全
倔强的石头1062 小时前
【Linux指南】Makefile入门:从概念到基础语法
linux·运维·服务器
ajassi20002 小时前
linux C 语言开发 (七) 文件 IO 和标准 IO
linux·运维·服务器
程序猿编码2 小时前
基于 Linux 内核模块的字符设备 FIFO 驱动设计与实现解析(C/C++代码实现)
linux·c语言·c++·内核模块·fifo·字符设备
一只游鱼2 小时前
Zookeeper介绍与部署(Linux)
linux·运维·服务器·zookeeper