07makefile学习之习题1
以下为相关makefile的学习文章
01makefile学习之GCC编译的四个阶段(带编译阶段、汇编阶段、-S,-c的区别)
02makefile学习之makefile的基本原则
03makefile学习之makefile的一个规则
04makefile学习之多个规则处理多个文件
05makefile学习之两个函数和一个特殊规则clean
06makefile学习之三个自动变量(@ , @,@,^,$<)和模式规则
07makefile学习之习题1
08makefile学习之习题2
1 习题1
环境:假设在当前目录day01有一个用于存放.c文件的目录src;一个用于存放.h文件的目录inc;有一个用于存放.o文件的目录obj。
要求:在当前目录day01编写makefile,用于编译inc,src内的文件,并将编译过程中生成的.o目标文件放在obj中。可执行程序放在当前目录。
解析:
这题非常简单,环境是模拟我们平时项目的实战环境,文件已经放置好,只需我们编写makefile即可。经过之前makefile的学习,我们只需要将中间生成的.o文件路径修改一下即可。
环境准备:
将hello.c的头文件全部拷贝至head.h。命令如下:
//1 进入src打开hello.c文件
vim hello.c
//2 用:vsp head.h多窗口编辑创建新文件,拷贝过去并且添加头文件唯一标识宏
:vsp head.h
//3 将head.h剪切至../inc
mv ./head.h ../inc/
这样我们就将上一次学习的环境准备好。
答案如下(用之前学习的例子举例)
之前的答案:
src = $(wildcard ./*.c)
obj = $(patsubst %.c,%.o,$(src)) #param bewteen is ","
debug = -Wall -g
ALL:hello
hello:$(obj)
gcc $(obj) -o $@
$(obj):%.o:%.c
gcc -c $< -o $@ $(debug)
clean:
-rm -rf $(obj)
本习题答案:
src = $(wildcard ./src/*.c) #src=./src/add.c ...
obj = $(patsubst ./src/%.c, ./obj/%.o ,$(src)) #%=add,obj=./obj/add
incl = ./inc #编译所需要的头文件
debug = -Wall -g
ALL:hello
hello:$(obj)
gcc $(obj) -o $@
$(obj):./obj/%.o:./src/%.c #
gcc -c $< -o $@ $(debug) -I $(incl) #只需要在编译加头文件,上面的链接不需要
clean:
-rm -rf $(obj)
.PHONY:clean ALL # 防止执行make clean当前目录有clean文件名而不能成功删除
结果为:
需要注意的一点是,hello.c中若不正确添加以下头文件的话,会出现隐式声明的警告。
#include"../inc/head.h"
2 对上面答案进行解释
1)由于我们要索引./src/目录下的所有.c文件,所以此时src的值为:
src=./src/hello.c,./src/add.c,./src/sub.c,./src/mul.c
2)此时第二行obj的产生1和2才是比较难的点。若我们仍按照上一次匹配的话,那么经过patsubst函数转换后:
对比:%.c,%.o
取src的第一个值举例;
src=./src/hello.c,那么此时%就是为:./src/hello
这样的话obj返回的值就为./src/hello.o,结果与我们题目要求的放置目标文件的路径./obj/不符合。
所以我们就需要让%号匹配的字符仅仅为函数名即可,具体路径我们可以自己配。
例如:
取src的第一个值举例;
src=./src/hello.c
若想使%匹配函数名,那么参数1就应该为./src/%.c=./src/hello.c
拿到函数名后,剩下就比较简单了,在函数名前补充我们想要放置的路径即可。所以参数2为:
./obj/%.o,填上名字后就是./obj/hello.o
其它文件也是同理。
3)正确拿到src和obj的返回路径后,就仍需要往下检查我们的makefile命令。先检查第一组,发现是不需要改的;然后第二组是模式规则,发现是需要修改的,因为不修改的话,%=函数名,而没有具体路径,所以它是无法找到对应文件的。例如当%=hello时,$(obj):hello.o:hello.c,当前目录是没有hello.o和hello.c,而是放在了obj和src中。所以必须修改。接着是第三组特殊的删除规则,不需要修改。
4)添加对应的头文件变量选项,只需要在编译时添加该选项即可。
5)每一次写makefile,在写完src和obj的变量后,都必须检查一遍每组规则的目标和依赖是否正确,养好良好的习惯。并且在使用makefile时注意加-n选项模拟删除。防止项目文件被删除。
3 这里额外的讲一下关于makefile的两个参数选项:
//1)
-n:模拟命令,并不会真正执行。
例如make -n make clean -n//分别模拟make和make clean
//2)
-f:指定名字不为makefile的文件执行makefile的功能
例如你当前目录下编写了一个叫m1的makefile文件,注意:不是makefile名字的文件执行make时是不会被系统执行的。
当我们加上-f就可以让系统执行。
make -f m1