在学习李云《驾驭Makefile》出现了一点问题,本着刨根问底,遇到问题不忽略,要搞明白的精神,要把遇到的问题解决,然后总结分享。
在李云《驾驭Makefile》:http://yunli.blog.51cto.com/831344/195759(感谢李大牛的无私奉献精神)
中模仿2.5节对Makefile后,进行编译,会不断的刷死循环,如图所示,怎么改都不对,不知为何。
.PHONY:clean all
CC=gcc
RM=rm
BIN_DIR=bin
OBJ_DIR=objs
MKDIR=mkdir
DIR_DEPS=deps
RM_OP=-rf
EXE=simple
EXE:=$(addprefix $(BIN_DIR)/, $(EXE))
SRC=$(wildcard *.c)
OBJS=$(patsubst %.c, %.o, $(SRC))
DIRS = $(BIN_DIR) $(OBJ_DIR) $(DIR_DEPS)
OBJS:=$(addprefix $(OBJ_DIR)/, $(OBJS))
DEPS = $(SRC:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
bar ?= $(OBJS:.o=.c)
all : $(EXE)
#1
-include $(DEPS)
$(DIRS):
$(MKDIR) $@
$(EXE):$(BIN_DIR) $(OBJS)
$(CC) -o $@ $(filter %.o, $^)
$(OBJ_DIR)/%.o: $(DEP_OBJ_DIR) %.c
$(CC) -o $@ -c $(filter %.c, $^)
#2
$(DIR_DEPS)/%.dep:$(DIR_DEPS) %.c
@echo "Making $@..."
@set -e;\
$(RM) $(RM_OP) $@;\
$(CC) -E -MM $(filter %.c, $^) > $@.tmp;\
sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@;\
$(RM) $(RM_OP) $@.tmp
clean:
$(RM) $(RM_OP) $(DIRS)
----------------------------------------------------------我是分隔符-------------------------------------------------------
引起问题的关键有两个地方,一个是采用include关键字,包含了.dep文件,二是.dep目录是生成.dep的先决条件(或称依赖关系)。
make在执行Makefile时,会先将依赖文件扫描一遍,如果在编译的过程中,被依赖文件变化了,(make查看文件时间戳),就会
重新编译过程,以保证将最新的变化编译进可执行文件,这一点毋庸置疑,是make的特点。而上面的Makefile之所以产生死循环,那是因为
生成.dep文件时,同时改变了dep文件目录的时间戳,对于make命令来说,作为生成.dep文件所依赖的.dep目录就不是最新的了,而这个目录是生成.dep的先决条件,所以需要重新建.dep文件
而构建.dep文件后,.dep文件目录又不是最新了,所以make会再次构建.dep文件,这就造成了死循环。
make --> 生成.dep文件 --> .dep目录时间戳变化 --> 重新make --> 生成.dep文件 --> .dep目录时间戳变化 --> 重新make.......
解决这个问题的方法就是,让已经存在.dep目录的时候,其目录就不要成为生成.dep的先决条件了,也就是去掉这层依赖关系,这样就不会重新编译.dep文件。
.PHONY:clean all
CC=gcc
RM=rm
BIN_DIR=bin
OBJ_DIR=objs
MKDIR=mkdir
DIR_DEPS=deps
RM_OP=-rf
EXE=simple
EXE:=$(addprefix $(BIN_DIR)/, $(EXE))
SRC=$(wildcard *.c)
OBJS=$(patsubst %.c, %.o, $(SRC))
DIRS = $(BIN_DIR) $(OBJ_DIR) $(DIR_DEPS)
OBJS:=$(addprefix $(OBJ_DIR)/, $(OBJS))
DEPS = $(SRC:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
bar ?= $(OBJS:.o=.c)
all : $(EXE)
ifeq ("$(wildcard $(DIR_DEPS))", "")
DEP_DIR_DEPS:=$(DIR_DEPS)
endif
-include $(DEPS)
$(DIRS):
$(MKDIR) $@
$(EXE):$(BIN_DIR) $(OBJS)
$(CC) -o $@ $(filter %.o, $^)
$(OBJ_DIR)/%.o: $(DEP_OBJ_DIR) %.c
$(CC) -o $@ -c $(filter %.c, $^)
#2
$(DIR_DEPS)/%.dep:$(DEP_DIR_DEPS) %.c
@echo "Making $@..."
@set -e;\
$(RM) $(RM_OP) $@;\
$(CC) -E -MM $(filter %.c, $^) > $@.tmp;\
sed 's,\(.*\)\.o[:]*,objs/\1.o $@:,g' < $@.tmp > $@;\
$(RM) $(RM_OP) $@.tmp
clean:
$(RM) $(RM_OP) $(DIRS)
可见在使用Makefile的依赖关系时,出现问题最好将依赖关系画图,理清依赖关系,以及注意make更新最新文件的特性,这样的问题还是能够避免的。