第13课 - 自动生成依赖关系(下)
1. 问题引入———如何在makefile中组织.dep
文件到指定目录?
解决思路:
当include发现.dep
文件不存在时:
1)通过规则和命令创建deps
文件夹
2)将所有.dep
文件创建到deps
文件夹
3).dep
文件中记录目标文件的依赖关系
初步代码设计:
编程实验:makefile.1
.PHONY : all clean MKDIR := mkdir RM := rm -fr CC := gcc DIR_DEPS := deps SRCS := $(wildcard *.c) DEPS := $(SRCS:.c=.dep) DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS)) include $(DEPS) all : @echo "all" $(DIR_DEPS) : $(MKDIR) $@ $(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c @echo "Creating $@ ..." @set -e; \ $(CC) -MM -E $(filter %.c, $^) | sed 's,\(.*\)\.o[ :]*,objs/\1.o : ,g' > $@ clean : $(RM) $(DIR_DEPS)
运行结果:
2. 不是问题的问题:为什么一些.dep依赖文件会被重复创建多次?
问题本质分析:
-
deps文件夹的时间属性会因为依赖文件创建而发生改变
-
make发现deps文件夹比对应的目标更新
-
触发相应的规则重新解析和命令执行
-
。。。。。。
解决方案优化:使用ifeq动态决定.dep目标的依赖
编程实验:makefile.2
.PHONY : all clean MKDIR := mkdir RM := rm -fr CC := gcc DIR_DEPS := deps SRCS := $(wildcard *.c) DEPS := $(SRCS:.c=.dep) DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS)) all : @echo "all" ifeq ("$(MAKECMDGOALS)", "all") -include $(DEPS) endif ifeq ("$(MAKECMDGOALS)", "") -include $(DEPS) endif $(DIR_DEPS) : $(MKDIR) $@ ifeq ("$(wildcard $(DIR_DEPS))", "") $(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c else $(DIR_DEPS)/%.dep : %.c endif @echo "Creating $@ ..." @set -e; \ $(CC) -MM -E $(filter %.c, $^) | sed 's,\(.*\)\.o[ :]*,objs/\1.o : ,g' > $@ clean : $(RM) $(DIR_DEPS)
运行结果:
3. include暗黑操作:
1)使用减号(-)不但关闭了include发出的警告,通过关闭了错误;当错误发生时make将忽略这些错误
2)如果include触发规则创建了文件,include的位置将替换为文件的内容;
编程实验:makefile.3
.PHONY : all -include test.txt all : @echo "this is all" test.txt : @echo "creating $@ ..." @echo "other : ; @echo "this is other" " > test.txt
运行结果:
3)如果include包含的文件存在,之后还会发生什么?
当include的文件存在时,并且对应的规则及其规则的依赖(依赖的时间戳比目标文件的时间戳更新时)也存在时,这个文件的规则命令将会被执行。
编程实验:makefile.4
.PHONY : all -include test.txt all : @echo "this is all" test.txt : b.txt @echo "creating $@ ..."
运行结果:
4. 关于include的总结
-
当目标文件不存在时:以文件名查找规则,并执行
-
当目标文件不存在时,且查找到的规则中创建了目标文件:将创建成功的目标文件中的内容包含进当前makefile
-
当目标文件存在时,将目标文件包含进当前makefile中,以目标文件名查找是否有相应的规则:
1)如果有:比较规则的依赖关系,决定是否执行规则的命令
2)如果没有:无操作
-
当目标文件存在,且目标名对应的规则被执行:
1)规则中的命令更新了目标文件:make重新包含目标文件,替换之前包含的内容
2)目标文件未被更新:无操作