You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Makefile中patsubst路径替换及头文件自动配置问题

解决Makefile的两个目录结构问题

问题1:统一OBJ目录下的目标文件,忽略源文件子目录

你现在的Makefile会保留源文件的目录结构来生成.o文件,要改成所有.o都直接放在OBJ/根目录,关键是提取源文件的文件名,丢弃路径,同时让Make能找到对应子目录里的.cpp文件。

修改步骤:

  1. 重新生成OBJECTFILES:用notdir函数去掉源文件的路径,只保留文件名,再加上OBJ/前缀:

    OBJECTFILES = $(addprefix $(OBJ), $(notdir $(SOURCEFILES:.cpp=.o)))
    

    或者用patsubst组合写法:

    OBJECTFILES = $(patsubst %.cpp,$(OBJ)%.o,$(notdir $(SOURCEFILES)))
    
  2. 调整编译规则,让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/子目录加入头文件搜索路径,二是自动生成头文件依赖,避免修改头文件后忘记重新编译。

修改步骤:

  1. 自动添加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))
    
  2. 自动生成头文件依赖
    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

火山引擎 最新活动