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

如何合并针对不同目录的Makefile编译构建规则?

合并Makefile冗余编译规则的解决方案

问题背景

最初编写了一条Makefile编译规则用于编译$(SDW_DIR)目录下的cpp文件,为了编译$(UTILS_DIR)下的文件,复制规则并添加了$(SDW_COMPILER_FLAGS)(让src/utils下的文件能直接用#include <File.h>替代相对路径引用)。两条规则均可正常运行,但写法冗余,希望合并为单条规则。

现有规则与变量定义

现有编译规则

$(BUILD_DIR)/%.o: $(SDW_DIR)%.cpp
    @mkdir -p $(BUILD_DIR)
    $(COMPILER) $(COMPILER_OPTIONS) -c -o $@ $^ $(SDL_COMPILER_FLAGS) $(GLM_COMPILER_FLAGS)

$(BUILD_DIR)/%.o: $(UTILS_DIR)%.cpp
    @mkdir -p $(BUILD_DIR)
    $(COMPILER) $(COMPILER_OPTIONS) -c -o $@ $^ $(SDL_COMPILER_FLAGS) $(GLM_COMPILER_FLAGS) $(SDW_COMPILER_FLAGS)

相关变量定义

SDW_DIR := ./libs/sdw/
UTILS_DIR := ./src/utils/
GLM_DIR := ./libs/glm-0.9.7.2/

SDW_SOURCE_FILES := $(wildcard $(SDW_DIR)*.cpp)
SDW_OBJECT_FILES := $(patsubst $(SDW_DIR)%.cpp, $(BUILD_DIR)/%.o, $(SDW_SOURCE_FILES))
UTILS_SOURCE_FILES := $(wildcard $(UTILS_DIR)*.cpp)
UTILS_OBJECT_FILES := $(patsubst $(UTILS_DIR)%.cpp, $(BUILD_DIR)/%.o, $(UTILS_SOURCE_FILES))

SDW_COMPILER_FLAGS := -I$(SDW_DIR)
UTILS_COMPILER_FLAGS := -I$(UTILS_DIR)
GLM_COMPILER_FLAGS := -I$(GLM_DIR)

合并方案

方案1:使用vpath+条件判断

通过vpath指定源文件搜索目录,在编译命令中用$(findstring)判断源文件路径,动态添加对应编译flags:

# 指定cpp源文件的搜索目录
vpath %.cpp $(SDW_DIR) $(UTILS_DIR)

# 统一编译规则
$(BUILD_DIR)/%.o: %.cpp
	@mkdir -p $(BUILD_DIR)
	$(COMPILER) $(COMPILER_OPTIONS) -c -o $@ $< \
		$(SDL_COMPILER_FLAGS) $(GLM_COMPILER_FLAGS) \
		$(if $(findstring $(UTILS_DIR),$<),$(SDW_COMPILER_FLAGS))

思路说明

  • vpath %.cpp $(SDW_DIR) $(UTILS_DIR):告诉Make在SDW_DIR和UTILS_DIR中查找匹配%.cpp的源文件
  • $(findstring $(UTILS_DIR),$<):检查当前编译的源文件($<)是否来自UTILS_DIR,如果是则返回该路径,否则为空
  • $(if ...):根据上述判断结果,决定是否添加SDW_COMPILER_FLAGS

方案2:使用静态模式规则+对象集合判断

先合并所有对象文件集合,再通过$(filter)判断当前对象是否属于UTILS模块,动态添加flags:

# 合并所有对象文件
ALL_OBJECT_FILES := $(SDW_OBJECT_FILES) $(UTILS_OBJECT_FILES)

# 静态模式编译规则
$(ALL_OBJECT_FILES): $(BUILD_DIR)/%.o:
	@mkdir -p $(BUILD_DIR)
	# 匹配SDW目录的源文件
	$(if $(filter $(SDW_OBJECT_FILES),$@),$(eval SRC := $(SDW_DIR)$*.cpp))
	# 匹配UTILS目录的源文件
	$(if $(filter $(UTILS_OBJECT_FILES),$@),$(eval SRC := $(UTILS_DIR)$*.cpp))
	$(COMPILER) $(COMPILER_OPTIONS) -c -o $@ $(SRC) \
		$(SDL_COMPILER_FLAGS) $(GLM_COMPILER_FLAGS) \
		$(if $(filter $(UTILS_OBJECT_FILES),$@),$(SDW_COMPILER_FLAGS))

思路说明

  • 先将SDW_OBJECT_FILES和UTILS_OBJECT_FILES合并为ALL_OBJECT_FILES作为静态模式的目标集合
  • 通过$(filter)判断当前目标对象属于哪个模块,动态设置对应的源文件路径
  • 同样用$(if)条件判断是否添加SDW_COMPILER_FLAGS

额外优化:提取通用编译flags

可以把所有模块都需要的flags提取为通用变量,让规则更简洁:

BASE_COMPILER_FLAGS := $(SDL_COMPILER_FLAGS) $(GLM_COMPILER_FLAGS)

# 对应方案1的规则可简化为
$(BUILD_DIR)/%.o: %.cpp
	@mkdir -p $(BUILD_DIR)
	$(COMPILER) $(COMPILER_OPTIONS) -c -o $@ $< \
		$(BASE_COMPILER_FLAGS) \
		$(if $(findstring $(UTILS_DIR),$<),$(SDW_COMPILER_FLAGS))

内容的提问来源于stack exchange,提问作者J P

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:15:42