Makefile中patsubst路径替换及头文件自动配置问题
解决Makefile的两个目录结构问题
问题1:统一OBJ目录下的目标文件,忽略源文件子目录
你现在的Makefile会保留源文件的目录结构来生成.o文件,要改成所有.o都直接放在OBJ/根目录,关键是提取源文件的文件名,丢弃路径,同时让Make能找到对应子目录里的.cpp文件。
修改步骤:
重新生成OBJECTFILES:用
notdir函数去掉源文件的路径,只保留文件名,再加上OBJ/前缀:OBJECTFILES = $(addprefix $(OBJ), $(notdir $(SOURCEFILES:.cpp=.o)))或者用
patsubst组合写法:OBJECTFILES = $(patsubst %.cpp,$(OBJ)%.o,$(notdir $(SOURCEFILES)))调整编译规则,让Make能找到子目录里的源文件:
原来的$(OBJ)%.o: $(SRC)%.cpp规则只能匹配Src/根目录的.cpp,要让Make搜索所有Src/的子目录,需要用vpath指定.cpp文件的搜索路径:# 告诉Make在Src/及其所有子目录里找.cpp文件 vpath %.cpp $(SRC) $(shell find $(SRC) -type d) # 编译规则改为匹配任意路径下的.cpp,生成OBJ根目录的.o $(OBJ)%.o: %.cpp $(CC) -c $< $(INC) -o $@
问题2:自动关联Src及其子目录的头文件
要自动处理两部分:一是把所有Src/子目录加入头文件搜索路径,二是自动生成头文件依赖,避免修改头文件后忘记重新编译。
修改步骤:
自动添加Src所有子目录到头文件搜索路径:
用find命令找出Src/下的所有子目录,再加上-I前缀加到INC变量里:INC = -I Lib/GLFW/include/\ -I Lib/GLAD/include/\ -I Lib/STB/\ -I Lib/GLM/\ -I Src/Header/ # 新增:自动添加Src/及其所有子目录到头文件搜索路径 INC += $(addprefix -I , $(shell find $(SRC) -type d))自动生成头文件依赖:
Make可以通过-MM/-MP选项生成依赖文件(.d),编译时自动包含这些依赖,确保修改头文件后相关源文件会重新编译:# 定义依赖文件路径(和.o文件同目录,后缀改为.d) DEPFILES = $(OBJECTFILES:.o=.d) # 包含所有依赖文件,不存在时忽略 -include $(DEPFILES) # 修改编译规则,添加生成依赖的参数 $(OBJ)%.o: %.cpp $(CC) -c $< $(INC) -o $@ -MM -MP -MF $(@:.o=.d)
修改后的完整Makefile
CC = g++ -g SRC = Src/ OBJ = Obj/ BIN = Bin/ INC = -I Lib/GLFW/include/\ -I Lib/GLAD/include/\ -I Lib/STB/\ -I Lib/GLM/\ -I Src/Header/ # 自动添加Src及其所有子目录到头文件搜索路径 INC += $(addprefix -I , $(shell find $(SRC) -type d)) LIB = -L Lib/GLFW/lib-mingw-w64 -lglfw3 -lopengl32 -lglu32 -lgdi32 EXE = $(BIN)Test.exe # 获取Src/所有子目录的.cpp文件 SOURCEFILES = $(wildcard $(SRC)**/*.cpp) # 生成OBJ根目录下的.o文件(忽略源文件路径) OBJECTFILES = $(addprefix $(OBJ), $(notdir $(SOURCEFILES:.cpp=.o))) # 定义依赖文件 DEPFILES = $(OBJECTFILES:.o=.d) # 包含依赖文件 -include $(DEPFILES) # 告诉Make在Src及其子目录找.cpp文件 vpath %.cpp $(SRC) $(shell find $(SRC) -type d) # 确保目录存在 $(shell mkdir -p $(OBJ) $(BIN)) all: $(EXE) $(EXE) : $(OBJECTFILES) $(CC) -o $@ $^ $(LIB) $(OBJ)%.o: %.cpp $(CC) -c $< $(INC) -o $@ -MM -MP -MF $(@:.o=.d)
注意事项:
- 如果项目里存在不同子目录下的同名.cpp文件,会导致.o文件互相覆盖,这种情况需要额外处理(比如给.o文件添加子目录前缀),但如果没有重名文件就无需担心。
内容的提问来源于stack exchange,提问作者Eric




