Makefile中make re未执行所有模式规则的问题排查
Make re执行时依赖文件未重新生成的问题与解决
问题描述
执行make re时出现异常:%.d模式规则会在fclean执行前触发,而fclean删除依赖文件后,后续all阶段仅调用%.o模式规则,未重新生成.d依赖文件。
make执行输出
mkdir -p srcs/depends c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -MM srcs/tests.cpp -o srcs/depends/tests.d c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -MM srcs/main.cpp -o srcs/depends/main.d mkdir -p srcs/obj c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -c srcs/main.cpp -o srcs/obj/main.o c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -c srcs/tests.cpp -o srcs/obj/tests.o c++ -lstdc++ srcs/obj/main.o srcs/obj/tests.o -o main
make re执行输出
rm -f -rv srcs/obj srcs/depends srcs/obj/main.o srcs/obj/tests.o srcs/obj srcs/depends/main.d srcs/depends/tests.d srcs/depends rm -f main mkdir -p srcs/obj c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -c srcs/main.cpp -o srcs/obj/main.o c++ -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -c srcs/tests.cpp -o srcs/obj/tests.o c++ -lstdc++ srcs/obj/main.o srcs/obj/tests.o -o main
原Makefile内容
NAME = main SRCSDIR = srcs SRCS = $(wildcard $(SRCSDIR)/*.cpp) OBJSDIR = srcs/obj OBJS = $(SRCS:$(SRCSDIR)/%.cpp=$(OBJSDIR)/%.o) DEPENDSDIR = srcs/depends DEPENDS = $(SRCS:$(SRCSDIR)/%.cpp=$(DEPENDSDIR)/%.d) CPPFLAGS = -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes DEPFLAGS = -MM LDFLAGS = -lstdc++ all: $(NAME) $(NAME): $(OBJS) c++ $(LDFLAGS) $^ -o $@ $(OBJSDIR)/%.o: $(SRCSDIR)/%.cpp | $(OBJSDIR) c++ $(CPPFLAGS) -c $< -o $@ $(DEPENDSDIR)/%.d: $(SRCSDIR)/%.cpp | $(DEPENDSDIR) c++ $(CPPFLAGS) $(DEPFLAGS) $< -o $@ $(OBJSDIR) $(DEPENDSDIR): mkdir -p $@ -include $(DEPENDS) clean: $(RM) -rv $(OBJSDIR) $(DEPENDSDIR) fclean: clean $(RM) $(NAME) re: fclean all .PHONY: all clean fclean re
原因分析
- Make在执行任何目标前,会先完成整个Makefile的解析过程,此时
-include $(DEPENDS)会触发%.d规则生成依赖文件(如果文件不存在或过时),这一步发生在fclean执行之前。 fclean删除.d文件后,Make已经完成了依赖解析,后续执行all时不会再重新触发%.d规则——因为Make认为这些依赖目标已经处理过,不会再检查文件是否存在。
解决方案
将依赖文件的生成逻辑整合到.o文件的编译规则中,利用编译器的自动依赖生成选项,避免单独的%.d规则,确保make re时能同步生成依赖文件。
修改后的Makefile
NAME = main SRCSDIR = srcs SRCS = $(wildcard $(SRCSDIR)/*.cpp) OBJSDIR = srcs/obj OBJS = $(SRCS:$(SRCSDIR)/%.cpp=$(OBJSDIR)/%.o) DEPENDSDIR = srcs/depends DEPENDS = $(SRCS:$(SRCSDIR)/%.cpp=$(DEPENDSDIR)/%.d) # 添加-MMD -MP自动生成依赖,-MMD生成不含系统头文件的依赖,-MP避免头文件删除时出错 CPPFLAGS = -Wall -Werror -Wextra -Wshadow -std=c++98 -pedantic -Iincludes -MMD -MP LDFLAGS = -lstdc++ all: $(NAME) $(NAME): $(OBJS) c++ $(LDFLAGS) $^ -o $@ # 编译.o时,通过-MF指定依赖文件输出到DEPENDSDIR $(OBJSDIR)/%.o: $(SRCSDIR)/%.cpp | $(OBJSDIR) $(DEPENDSDIR) c++ $(CPPFLAGS) -c $< -o $@ -MF $(DEPENDSDIR)/$*.d $(OBJSDIR) $(DEPENDSDIR): mkdir -p $@ -include $(DEPENDS) clean: $(RM) -rv $(OBJSDIR) $(DEPENDSDIR) fclean: clean $(RM) $(NAME) re: fclean all .PHONY: all clean fclean re
方案说明
- 使用
-MMD -MP编译器选项,自动生成依赖文件,无需单独写%.d规则。 - 通过
-MF $(DEPENDSDIR)/$*.d指定依赖文件的输出目录,保持文件结构整洁。 - 每次编译
.o文件时会同步生成对应的.d文件,make re执行fclean后,重新编译.o时会自动生成新的依赖文件,彻底避免原规则的时机问题。
内容的提问来源于stack exchange,提问作者Hiromasa
相关产品推荐
相关产品推荐

