第一个版本的makefile
Makefile的依赖是从上至下的,换句话说就是目标文件是第一句里的目标,如果不满足执行依赖,就会继续向下执行。如果满足了生成目标的依赖,就不会再继续向下执行了。
Make会自动寻找依赖条件所用到的文件,
其中,我们可以在中makefile文件中一次执行多个文件,执行命令是make,文件名可以是makefile或是Makefile,必须是这个名字,因为make与之匹配,
在其中我们可以
Makefile是一个脚本文件,该文件存放的是shell命令,既然是脚本文件,就要遵守makefile制定的规则(显示规则)。所以最开始的makefile可以是这样的
前面的hello是所需生成的目标文件,后面的hello.c是生成目标文件所需的依赖文件,
为了将编译的整个过程体现出来,Makefile中的内容可以如下
执行Make指令之后的文件如下
但是hello.i hello.s这些文件都是我们不需要的,所以不需要这么多步骤,hello依赖于hello.o,hello.o依赖于hello.c。所以改写makefile的内容
执行Make指令之后的文件如下所示
以上是对单个文件进行编写的makefile,如果是多文件编程的话,应该怎么编写makefile文件?假设文件有add.c mul.c div.c main.c四个文件
Main.c
Add.c
Mul.c
div.c
对于这四个文件,makefile文件中可以这样写
执行make指令后是这样的
但是这样的makefile是存在问题的,当我修改其中的一个文件后,其他三个文件就必须跟着一起重新编译,效率太低。比如改写add.c文件
其他三个文件也一起被编译了一遍。
总共有四个文件,需要生成main可执行文件,main依赖于add.o、mul.o、div.o,这三个文件又分别依赖于各自的.c文件,所以makefile可以改写成这样
执行make指令后
此时去修改其中任一个文件,其他文件不会被重新编译,比如修改add.c
修改完之后再重新make一下,发现其他文件并没有被重新编译,只执行了 编译add.c和链接.o文件这两个动作
为什么会仅执行这两个动作呢?
Makefile的检测原理:
文件有一个属性叫做“修改时间”,当文件被修改后,这个属性就会发生改变。Make就是通过检测这个属性判断哪些文件有没有被修改过。
如果出现目标文件的“修改时间”比依赖文件的“修改时间“更早的话,比如 16:40 早于 16:41。这样的话,make就会重新执行这条规则(重新编译);
Add.o依赖于add.c。add.c 是依赖文件,add.o是目标文件,add.c一被修改,时间就比add.o更晚。所以gcc -c add.c -o add.o 这条规则会重新被执行。一执行后,add.o的时间就比main的时间更晚,所以gcc main.o add.o mul.o div.o 这条规则也会被执行。
关于makefile中的变量
变量的定义:
变量名 = 目标名 等价于 替换功能
变量的使用:
$(变量名)
关于makefile指定最终生成目标问题
Makefile默认将第一条目标视作最终目标,一旦最终目标生成后,其他指令不会继续执行,当将main: add.o mul.o div.o 移到最后时
再去执行make指令,仅仅会生成一个main.o文件,其他文件不会被生成。
再将mul.o:mul.c放在第一条目标验证一下
执行make指令后,只生成了mul.o
所以可以通过ALL:(最终目标)去指定一个最终目标,ALL需要放在第一条语句
执行完make指令后
Makefile的两个函数和伪目标
src = $(wildcard *.c)
函数名:wildcard
函数功能:找到当前目录下所有后缀为.c的文件,将文件名组成列表,赋值给src
结果: src = add.c div.c mul.c main.c
obj = $(patsubst %.c,%.o, $(src))
函数名:patsubset
函数功能:将参数3($(src))中,包含参数1(%.c)的部分,替换成参数2
$(src)是一个列表,%会依次顺序遍历列表中的.c文件
结果:obj = add.o div.o mul.o main.o
根据这两个函数,所以makefile可以改写成这样
执行make指令后
关于伪目标的问题
在上面的makefile文件中,每次都需要删除.o文件,很繁琐,所以在makefile文件中加了删除部分
通过执行make clean指令可以删除多余的.o文件
rm前面的-,代表出错依然执行。
Make clean -n 是模拟删除动作,并未真正删除,看到模拟执行后,确定没有问题,执行删除动作
但是如果你在当前目录下去创建一个clean文件,当你执行make clean的时候系统就会认为你要执行clean文件,从而干扰原本的执行命令。
此时可以在makefile文件中的伪目标clean前加上.PHONY:来指定伪目标从而去除干扰:
此时再次执行make clean看一下效果:
这时候就算在本文件下有clean文件也不会造成干扰。
在上面的makefile中,各个生成.o的指令还是很繁琐,应该怎么办?
关于makefile3个自动变量和模式规则的问题
3个自动变量
$@ :在规则命令中,表示规则中的目标
$^ :在规则命令中,表示所有的依赖条件
$<:这个只能使用在规则命令中,表示规则中的第一个依赖条件。如果将该变量使用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则。
所以可以将makefile改写成这个样子,sub,add这些指令中使用$<和$^都能达到效果,但是为了模式规则,所以使用的$<
执行make指令后
上面的makefile不能进行扩展,可扩展性不行。比如,要添加一个乘法函数,就需要在makefile里面增加乘法函数的部分。不科学,所以,模式规则就来了
%.o:%.c
gcc -c $< -o $@
修改makefile,如下
执行make指令
此时再添加一个乘法函数,无须更改makefile。
扩展:
当文件中存在clean文件时,make失灵
添加一个伪代码
再使用变量完善一下