如何在Makefile中根据编译参数排除未使用的源文件?
项目结构
[22:58:45] BasicProject$ tree -l . ├── Makefile └── SourceCode ├── Controllers │ ├── MenuPage.cpp │ ├── MenuPage.hpp │ └── Unused.cpp ├── main.cpp ├── main.hpp └── Visuals -> ../AnotherProject/SourceCode/Visuals ├── Components │ └── Text.hpp ├── MenuPage.cpp └── MenuPage.hpp
问题描述
在BasicProject/SourceCode/Controllers目录下存在未被任何源文件引用的Unused.cpp,希望将这类未使用的文件排除出编译流程。且未使用的文件会随目标架构、库选择等编译参数变化而改变。
当前使用的简化版Makefile
PRJ_NAME := BasicProject ### Paths ### PRJ_ROOT := ./ PRJ_SOURCE_CODE := ${PRJ_ROOT}/SourceCode PRJ_OUTPUT_DIR := ${PRJ_ROOT}/Outputs PRJ_OBJECTS_DIR := ${PRJ_OUTPUT_DIR}/Objects INCLUDES += -I${PRJ_SOURCE_CODE} ### Derived Variables ### CPP_SRC_FILES := $(shell find -L $(PRJ_SOURCE_CODE) -type f -name "*.cpp" -print) CPP_OBJECTS := $(patsubst $(PRJ_SOURCE_CODE)/%.cpp,$(PRJ_OBJECTS_DIR)/%.o, $(CPP_SRC_FILES)) ### Targets ### all: $(CPP_OBJECTS) @g++ -o ${PRJ_OUTPUT_DIR}/${PRJ_NAME}.elf $(CPP_OBJECTS) clean: rm -rf ${PRJ_OBJECTS_DIR} ${PRJ_OBJECTS_DIR}/%.o : $(PRJ_SOURCE_CODE)/%.cpp @mkdir -p $(@D) @g++ $(INCLUDES) -c $< -o $@
解决方案
针对动态变化的未使用文件,有三种可行的处理方式:
1. 基于编译依赖自动推导(推荐)
利用Make的依赖管理特性,从入口文件(如main.cpp)递归推导所有被引用的源文件,替代全量收集的方式:
PRJ_NAME := BasicProject ### Paths ### PRJ_ROOT := ./ PRJ_SOURCE_CODE := ${PRJ_ROOT}/SourceCode PRJ_OUTPUT_DIR := ${PRJ_ROOT}/Outputs PRJ_OBJECTS_DIR := ${PRJ_OUTPUT_DIR}/Objects INCLUDES += -I${PRJ_SOURCE_CODE} # 入口文件,从这里开始推导依赖 MAIN_SRC := $(PRJ_SOURCE_CODE)/main.cpp CPP_SRC_FILES := $(MAIN_SRC) # 递归查找所有被引用的源文件(基于头文件与源文件的命名对应关系) define find_deps $(foreach h,$(shell g++ $(INCLUDES) -MM $1 | sed 's/.*://; s/\\//g; s/ /\n/g'), \ $(if $(filter %.hpp,$h), \ $(if $(wildcard $(patsubst %.hpp,%.cpp,$h)), \ $(eval CPP_SRC_FILES += $(patsubst %.hpp,%.cpp,$h)) \ $(call find_deps,$(patsubst %.hpp,%.cpp,$h)) \ ) \ ) \ ) endef $(call find_deps,$(MAIN_SRC)) # 对收集到的源文件去重 CPP_SRC_FILES := $(sort $(CPP_SRC_FILES)) CPP_OBJECTS := $(patsubst $(PRJ_SOURCE_CODE)/%.cpp,$(PRJ_OBJECTS_DIR)/%.o, $(CPP_SRC_FILES)) ### Targets ### all: $(PRJ_OUTPUT_DIR)/${PRJ_NAME}.elf $(PRJ_OUTPUT_DIR)/${PRJ_NAME}.elf: $(CPP_OBJECTS) @g++ -o $@ $^ clean: rm -rf ${PRJ_OBJECTS_DIR} ${PRJ_OUTPUT_DIR}/${PRJ_NAME}.elf ${PRJ_OBJECTS_DIR}/%.o : $(PRJ_SOURCE_CODE)/%.cpp @mkdir -p $(@D) @g++ $(INCLUDES) -c $< -o $@
2. 动态排除列表
设置可随编译参数调整的排除变量,根据不同编译场景指定要排除的文件:
# 默认排除的文件 EXCLUDE_SRC := # 根据编译参数添加对应排除项 ifeq ($(ARCH),arm) EXCLUDE_SRC += $(PRJ_SOURCE_CODE)/Controllers/Unused.cpp endif # 收集所有cpp文件后过滤掉排除列表中的文件 CPP_SRC_FILES := $(filter-out $(EXCLUDE_SRC), $(shell find -L $(PRJ_SOURCE_CODE) -type f -name "*.cpp" -print))
使用时通过make ARCH=arm触发对应的排除规则即可。
3. 标记式过滤
在未使用的文件开头添加特定标记(如// UNUSED),然后用grep过滤掉带标记的文件:
CPP_SRC_FILES := $(shell find -L $(PRJ_SOURCE_CODE) -type f -name "*.cpp" -exec grep -L "// UNUSED" {} \;)
这种方式需要手动标记文件,但实现简单,适合小型项目。
内容的提问来源于stack exchange,提问作者Caglayan Dokme
相关产品推荐
相关产品推荐

