多层目录C++项目编写支持增量编译的Makefile问题求助
问题根因
- 你在生成目标文件名时调用了
notdir丢弃了源文件的路径信息,配套的编译规则要求.cpp文件必须存放在项目根目录,子目录下的源文件无法被make定位,直接触发「无规则生成目标」的报错。 - 现有写法存在隐性bug:如果不同子目录下存在同名
.cpp文件,生成的.o文件会互相覆盖,最终链接阶段会出现符号错误。 - 额外的规则匹配错误:你给每个源文件名称直接加了
.o后缀,最终目标文件名格式为xxx.cpp.o,但你写的编译规则$(ObjectsDir)/%.o: %.cpp匹配时,会把xxx.cpp识别为通配符匹配内容,推导出来的依赖文件为xxx.cpp.cpp,完全不符合预期。
解决方案
方案1:保留所有目标文件统一放在Objects根目录的需求
适合确定项目中不会出现同名.cpp文件的场景,修改点如下:
- 新增源文件搜索路径配置VPATH,让make自动到子目录下搜索对应源文件
- 修改编译规则匹配你的
xxx.cpp.o命名格式
完整修改后的Makefile如下:
Appname := App ObjectsDir := ./Objects # 检索所有源文件 SrcFiles = $(shell find . -name "*.cpp") # 提取所有源文件所在目录,用于VPATH搜索 SrcDirs := $(dir $(SrcFiles)) VPATH := $(sort $(SrcDirs)) # 生成目标文件名:xxx.cpp -> ./Objects/xxx.cpp.o SrcFilesName = $(notdir $(SrcFiles)) Objects = $(addprefix ./Objects/, $(addsuffix .o, $(SrcFilesName))) # 编译配置 CXX = g++ CXXFLAGS = -Wall -std=c++20 -fsanitize=address CPPFLAGS = -DDEBUG -I ./Game/Headers -I ./Engine/Headers -I ./Engine/Headers/External LDLIBS = $(shell sdl2-config --libs) -l dl # 依赖文件引入,用于增量编译识别头文件修改 -include $(Objects:.o=.d) all : $(Appname) $(Appname) : $(Objects) $(CXX) $(CXXFLAGS) $(Objects) -o $(Appname) $(LDLIBS) # 修改后的编译规则,匹配xxx.cpp.o的命名格式 $(ObjectsDir)/%.cpp.o: %.cpp mkdir -p $(ObjectsDir) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MP -c $< -o $@ .PHONY: clean clean: rm -rf $(ObjectsDir) $(Appname)
方案2:更稳妥的目录结构保留方案(推荐)
在Objects目录下保留源文件的原有目录结构,从根源避免同名文件冲突,同时命名更符合常规xxx.o的格式,完整代码如下:
Appname := App ObjectsDir := ./Objects # 检索所有源文件 SrcFiles := $(shell find . -name "*.cpp") # 生成目标文件名:./Engine/Engine.cpp -> ./Objects/Engine/Engine.o Objects := $(patsubst %.cpp, $(ObjectsDir)/%.o, $(SrcFiles)) # 编译配置 CXX = g++ CXXFLAGS = -Wall -std=c++20 -fsanitize=address CPPFLAGS = -DDEBUG -I ./Game/Headers -I ./Engine/Headers -I ./Engine/Headers/External LDLIBS = $(shell sdl2-config --libs) -l dl # 引入依赖文件,支持头文件修改触发增量编译 -include $(Objects:.o=.d) all : $(Appname) $(Appname) : $(Objects) $(CXX) $(CXXFLAGS) $(Objects) -o $(Appname) $(LDLIBS) # 编译规则,自动创建对应子目录 $(ObjectsDir)/%.o: %.cpp mkdir -p $(dir $@) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MP -c $< -o $@ .PHONY: clean clean: rm -rf $(ObjectsDir) $(Appname)
内容的提问来源于stack exchange,提问作者Ymmit
相关产品推荐
相关产品推荐

