Makefile目标模式匹配失败求助:依赖规则写法报错解析
你的问题核心在于模式规则的目标模式和实际生成的带路径目标不匹配,我来一步步帮你理清原因和解决方法:
问题根源
当你写$(LOCAL_DEPENDS):.%.d:%.cpp时,LOCAL_DEPENDS展开后是类似./utils/.StrUtils.d这种带目录前缀的目标,但你的模式.%.d仅匹配当前目录下以.开头、.d结尾的文件,完全匹配不到带./utils/路径的目标,所以Make才会抛出“target `utils/.StrUtils.d' doesn't match the target pattern”的错误。
而直接写.%.d:%.cpp时,这是一个通用隐式模式规则,Make会自动处理目标的路径部分:它会把./utils/.StrUtils.d拆解为目录./utils/和文件名.StrUtils.d,然后用文件名去匹配.%.d模式,这样就能正确找到对应的源文件./utils/.StrUtils.cpp,所以规则能正常运行。
具体解决方法
针对你的完整代码,有两种可靠的修复方式:
方式一:使用静态模式规则(推荐)
静态模式规则可以明确绑定目标列表和模式,适配带路径的目标。把你原来的两个报错规则替换成:
# 处理cpp文件的依赖生成 $(LOCAL_DEPENDS): %.d: %.cpp @set -e; rm -f $@;\ $(CXX) -MM $(CFLAGS) $(LOCAL_INC) $< > $@.$$$$;\ sed 's,\($*\)\.o[:]*.,\1.o $@:,g' < $@.$$$$ > $@;\ rm $@.$$$$ # 处理hpp文件的依赖生成 $(LOCAL_HPP): %.d: %.hpp @set -e; rm -f $@;\ $(CXX) -MM $(CFLAGS) $(LOCAL_INC) $< > $@.$$$$;\ sed 's,\($*\)\.o[:]*.,\1.o $@:,g' < $@.$$$$ > $@;\ rm $@.$$$$
这里的%.d会匹配LOCAL_DEPENDS/LOCAL_HPP里的每个带路径目标,%会自动替换为目标的完整前缀(比如./utils/.StrUtils),对应的依赖%.cpp/%.hpp就会准确指向你的源文件/头文件。
方式二:保留通用隐式模式规则
如果你更倾向于用隐式规则,直接去掉规则前的$(LOCAL_DEPENDS):和$(LOCAL_HPP):前缀即可,让规则成为全局通用的:
# 全局通用的cpp依赖生成规则 .%.d: %.cpp @set -e; rm -f $@;\ $(CXX) -MM $(CFLAGS) $(LOCAL_INC) $< > $@.$$$$;\ sed 's,\($*\)\.o[:]*.,\1.o $@:,g' < $@.$$$$ > $@;\ rm $@.$$$$ # 全局通用的hpp依赖生成规则 .%.d: %.hpp @set -e; rm -f $@;\ $(CXX) -MM $(CFLAGS) $(LOCAL_INC) $< > $@.$$$$;\ sed 's,\($*\)\.o[:]*.,\1.o $@:,g' < $@.$$$$ > $@;\ rm $@.$$$$
Make会自动将这个规则应用到所有符合.%.d格式的目标上,不管它们在哪个子目录里。
额外优化建议
你代码里的LOCAL_DEPENDS赋值可以简化一下,当前的两行可以合并为一行,避免冗余处理:
LOCAL_DEPENDS := $(foreach file, $(LOCAL_SRC), $(dir $(file)).$(basename $(notdir $(file))).d)
修改后的完整Makefile示例:
TARGET := ./bin/Main CC := gcc CXX := g++ CFLAGS := -lpthread -g -Wall LFLAGS := -L./lib INC_DIR :=./utils . SRC_DIR :=./utils . LOCAL_SRC := $(foreach dir, $(SRC_DIR), $(wildcard $(dir)/*.cpp $(dir)/*.c $(dir)/*.cc)) LOCAL_HPP := $(foreach dir, $(SRC_DIR), $(wildcard $(dir)/*.hpp)) LOCAL_INC := $(addprefix -I, $(INC_DIR)) LOCAL_OBJS = $(patsubst %.cpp,%.o, $(patsubst %.c,%.cpp,$(patsubst %.cc,%.cpp,$(LOCAL_SRC)))) LOCAL_DEPENDS := $(foreach file, $(LOCAL_SRC), $(dir $(file)).$(basename $(notdir $(file))).d) LOCAL_HPP := $(foreach file, $(LOCAL_HPP), $(dir $(file)).$(basename $(notdir $(file))).d) $(TARGET): $(LOCAL_OBJS) $(CXX) $(CFLAGS) $(LOCAL_OBJS) -o $@ $(LOCAL_INC) $(LOCAL_OBJS):%.o:%.cpp $(CXX) $(CFLAGS) -c $< -o $@ $(LOCAL_INC) -include $(LOCAL_DEPENDS) $(LOCAL_DEPENDS): %.d: %.cpp @set -e; rm -f $@;\ $(CXX) -MM $(CFLAGS) $(LOCAL_INC) $< > $@.$$$$;\ sed 's,\($*\)\.o[:]*.,\1.o $@:,g' < $@.$$$$ > $@;\ rm $@.$$$$ -include $(LOCAL_HPP) $(LOCAL_HPP): %.d: %.hpp @set -e; rm -f $@;\ $(CXX) -MM $(CFLAGS) $(LOCAL_INC) $< > $@.$$$$;\ sed 's,\($*\)\.o[:]*.,\1.o $@:,g' < $@.$$$$ > $@;\ rm $@.$$$$ clean: rm -f $(TARGET); rm -f $(LOCAL_OBJS); rm -f $(LOCAL_DEPENDS); rm -f $(LOCAL_HPP)
内容的提问来源于stack exchange,提问作者trueno

