1. makefile基础规则
makefile: 管理项目。
命名:makefile makefile --- make 命令
1 个规则:
目标:依赖条件
(一个tab缩进)命令
1. 目标的时间必须晚于依赖条件的时间,否则,更新目标
2. 依赖条件如果不存在,找寻新的规则去产生依赖条件。
all:指定 makefile 的终极目标。
2 个函数:
src = $(wildcard ./*.c): 匹配当前工作目录下的所有.c 文件。将文件名组成列表,赋值给变量 src。 src = add.c sub.c div1.c
obj = $(patsubst %.c, %.o, $(src)): 将参数3中,包含参数1的部分,替换为参数2。 obj = add.o sub.o div1.o
clean: (没有依赖)
-rm -rf $(obj) a.out “-”:作用是,删除不存在文件时,不报错。顺序执行结束。
3 个自动变量:
$@: 在规则的命令中,表示规则中的目标。
$^: 在规则的命令中,表示所有依赖条件。
$<: 在规则的命令中,表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依赖条件列表中的依赖依次取出,套用模式规则。
模式规则:
%.o:%.c
gcc -c $< -o %@
静态模式规则:
$(obj):%.o:%.c
gcc -c $< -o %@
伪目标:
.phony: clean all
参数:
-n:模拟执行make clean 命令。
-f:指定文件执行 make 命令。
下面来一步一步升级makefile
第一个版本的makefile:
makefile的依赖是从上至下的,换句话说就是目标文件是第一句里的目标,如果不满足执行依赖,就会继续向下执行。如果满足了生成目标的依赖,就不会再继续向下执行了。
make会自动寻找规则里需要的材料文件,执行规则下面的行为生成规则中的目标。
执行make指令
运行hello,没有问题
2. makefile的一个规则
第二个版本的makefile:
test.c如下:
此时要进行编译,则需要多文件联合编译:
gcc test.c add.c sub.c div1.c -o a.out
对这个新的代码,写出下面的makefile
执行:
此时,修改add.c为下图
此时,再使用make,发现了问题
可以看到,只修改add.c,但是编译的时候,其他.c文件也重新编译了,这不太科学。
明明只改了一个,全部都重新编译了
于是将makefile改写如下:
执行make指令, 执行程序输出如下:
此时修改sub为下图:
再次make
可以看到,只重新编译了修改过的sub.c和最终目标
执行程序:
makefile检测原理:
修改文件后,文件的修改时间发生变化,会出现目标文件的时间早于作为依赖材料的时间,出现这种情况的文件会重新编译。
修改sub.c后,sub.o的时间就早于sub.c ,a.out的时间也早于sub.o的时间了,于是重新编译这俩文件了。
关于makefile指定目标问题,先修改makefile如下:
只是将a.out放在了文件末尾
执行make,如下:
这是因为,makefile默认第一个目标文件为终极目标,生成就跑路,这时候可以用all来指定终极目标
指定目标的makefile
执行:
3. makefile两个函数和clean
src = $(wildcard *.c)
匹配当前工作目录下的所有.c 文件。将文件名组成列表
赋值给变量 src:src = add.c sub.c div1.c
obj = $(patsubset %.c,%.o, $(src))
把src变量里所有后缀为.c的文件替换成.o
将参数3中,包含参数1的部分,替换为参数2。 obj = add.o sub.o div1.o
clean: (没有依赖)
-rm -rf $(obj) a.out
“-”:作用是,删除不存在文件时,不报错。顺序执行结束。
用这两个函数修改makefile如下:
执行,make指令,如下所示:
每次要删除.o文件,很恶心,于是改写makefile如下:
加了clean部分
rm前面的-,代表出错依然执行。比如,待删除文件集合是5个,已经手动删除了1个,就只剩下4个,然而删除命令里面还是5个的集合,就会有删除不存在文件的问题,不加这-,就会报错,告诉你有一个文件找不到。加了-就不会因为这个报错。
执行make:
由于没有文件变动,a.out的时间戳晚于所有依赖文件,这里make就没干活
于是,执行时加新指令,先模拟执行clean部分:
可以看到模拟执行后,会删除哪些文件。
确定没有问题,执行
4. makefile3个自动变量和模式规则
3个自动变量
$@ :在规则命令中,表示规则中的目标。
$< :在规则命令中,表示规则中的第一个依赖条件,如果将该变量用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则。
$^ :在规则命令中,表示规则中的所有依赖条件,组成一个列表,以空格隔开,如果这个列表中有重复项,则去重。
用自动变量修改makefile,如下:
sub,add这些指令中使用$<和$^都能达到效果,但是为了模式规则,所以使用的 $<
执行make,如下:
上面这个makefile,可扩展性不行。比如,要添加一个乘法函数,就需要在makefile里面增加乘法函数的部分。不科学,所以,模式规则
%.o:%.c
gcc -c $< -o $@
修改makefile,如下:
这时,增加一个mul函数,并添加mul.c文件如下:
执行make:
增加函数的时候,不用改makefile,只需要增加.c文件,改一下源码,就行。很强势。
继续优化makefile,使用静态模式规则,就是指定模式规则给谁用,这里指定模式规则给obj用,以后文件多了,文件集合会有很多个,就需要指定哪个文件集合用什么规则
$(obj):%.o:%.c
gcc -c $< -o $@
修改后makefile如下:
扩展
当前文件夹下有all文件或者clean文件时,会导致makefile瘫痪,如下所示,make clean没有工作
用伪目标来解决,添加一行 .phony: clean all
makefile如下所示:
再来执行make clean,就不会受到干扰了
还有一个扩展就是,编译时的参数,-g,-wall这些,可以放在makefile里面
修改后makefile如下:
执行makefile,如下:
练习一
源码add.c,sub.c这些在src目录下,.o文件要放在obj目录下,头文件head.h在inc目录下。
如下所示:
首先,将hello.c中的头文件单独拿出来
如下:
修改makefile如下,主要是注意%的匹配理解,只匹配文件名,目录位置要手动添加
执行一波,如下:
可以说是非常强势了
调用clean删除文件,直接用就行
如果makefile的名字变化一下,比如,叫m6
用m6执行makefile, make -f m6
用m6执行clean make -f m6 clean
练习二
编写一个 makefile 可以将其所在目录下的所有独立 .c 文件编译生成同名可执行文件。
将当前目录下所有.c文件编译为可执行程序
测试程序:
测试: