如何合并针对不同目录的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
相关产品推荐
相关产品推荐

