目录
1.问题
如何在makefile中组织.dep文件到指定目录?
2.解决思路
- 当include发现.dep文件不存在:
1.通过规则和命令创建deps文件
2.将所有.dep文件创建到deps文件夹
3..dep文件中记录目标文件的依赖关系
3.初步的代码设计
这样就是先生成dep文件在创建,目录
打开警告,发现include时找不到DEPS目标所以报错,如果不打开-include就会执行all
完善如下,我们使用预定义函数过滤掉目录
.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)
4.不是问题的问题
为什么有一些.dep依赖文件会被重复创建多次?
5.问题本质分析
- deps文件夹的时间属性会依赖文件创建而发生改变
- make发现deps文件夹比对应的目标更新
- 触发相应规则的重新解析和命令的执行
6.解决方案优化
使用ifeq动态决定.dep目标的依赖
make clean不需要include,完善如下
.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)
7.include暗黑操作一:
使用减号(-)不但关闭了include发出的警告,同时关闭了错误;当错误反生时make将忽略这些错误!
8.include暗黑操作二
如果include触发规则创建了文件,之后还会发生什么?
答:先执行创建在回去执行all
.PHONY : all
-include test.txt
all :
@echo "this is all"
test.txt :
@echo "creating $@ ..."
@echo "other : ; @echo "this is other" " > test.txt
9.include暗黑操作三
如果include包含的文件存在,之后还会发生什么?
答:将不再执行test这条规则
.PHONY : all
-include test.txt
all :
@echo "this is all"
test.txt :
@echo "creating $@ ..."
10.关于include的总结一
- 当目标文件不存在
以文件名查找规则,并执行
- 当目标文件不存在,且查找的规则中创建了目标文件
将创建成功的目标文件包好进当前makefile
11.关于include的总结二
- 当目标文件存在
将目标文件包含进当前makefile
以目标文件名查找是否有相应规则
12.关于include的总结三
- 当目标文件存在,且目标名对应的规则被执行
规则中的命令更新了目标文件
√make重新包含目标文件,替换之前包含的内容
目标文件未被更新
√NULL(无操作)
.PHONY : all
-include test.txt
all :
@echo "$@ : $^"
test.txt : b.txt
@echo "creating $@ ..."
@echo "all : c.txt" > test.txt