You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多层目录C++项目编写支持增量编译的Makefile问题求助

问题根因
  • 你在生成目标文件名时调用了notdir丢弃了源文件的路径信息,配套的编译规则要求.cpp文件必须存放在项目根目录,子目录下的源文件无法被make定位,直接触发「无规则生成目标」的报错。
  • 现有写法存在隐性bug:如果不同子目录下存在同名.cpp文件,生成的.o文件会互相覆盖,最终链接阶段会出现符号错误。
  • 额外的规则匹配错误:你给每个源文件名称直接加了.o后缀,最终目标文件名格式为xxx.cpp.o,但你写的编译规则$(ObjectsDir)/%.o: %.cpp匹配时,会把xxx.cpp识别为通配符匹配内容,推导出来的依赖文件为xxx.cpp.cpp,完全不符合预期。
解决方案

方案1:保留所有目标文件统一放在Objects根目录的需求

适合确定项目中不会出现同名.cpp文件的场景,修改点如下:

  1. 新增源文件搜索路径配置VPATH,让make自动到子目录下搜索对应源文件
  2. 修改编译规则匹配你的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 20:48:00