Makefile中的死循环问题--学习李云《驾驭Makefile》中的疑惑解决

来源:互联网 发布:soap rest 知乎 编辑:程序博客网 时间:2024/06/05 15:19
    在学习李云《驾驭Makefile》出现了一点问题,本着刨根问底,遇到问题不忽略,要搞明白的精神,要把遇到的问题解决,然后总结分享。

    在李云《驾驭Makefile》:http://yunli.blog.51cto.com/831344/195759(感谢李大牛的无私奉献精神)中模仿2.5节对Makefile后,进行编译,会不断的刷死循环,如图所示,怎么改都不对,不知为何。


先把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更新最新文件的特性,这样的问题还是能够避免的。