Makefile自动依赖生成仍编译已排除源文件的问题解决
问题根因
两个核心问题叠加导致过滤规则完全失效:
- 通配符兼容性问题:GNU Make 4.3以下版本(目前绝大多数开发环境的默认版本,比如Ubuntu 20.04、Windows下常见的MinGW配套make都属于这个范围)默认不支持
**递归通配符。你写的$(wildcard Core/**/*.c)、$(wildcard Drivers/STM32WBxx_HAL_Driver/**/*.c)实际不会递归遍历子目录找C文件,直接导致CORE_SOURCES、DRIVER_SOURCES变量的枚举结果完全不对——你想过滤的Core/Src/main.c从一开始就没被纳入C_SOURCES的匹配范围,filter-out自然没有任何作用。 - 旧构建残留干扰:你之前用CubeMX默认生成的Makefile编译过,build目录下残留了大量
.d依赖文件。Makefile末尾的-include $(wildcard $(BUILD_DIR)/*.d)会把这些旧依赖全部加载进来,旧依赖里明确记录了Core/Src/main.c以及其他Core、Drivers目录下源文件的编译规则,哪怕你现在的C_SOURCES里没写这些文件,make也会按照旧依赖的规则去编译、链接它们。这也是为什么你改了C_SOURCES之后依然能编译成功——实际参与编译的源文件大部分是旧依赖拉进来的,根本不是你新定义的C_SOURCES列表里的内容。 - 额外隐患:你用
notdir抹除了所有源文件的路径前缀生成.o文件,不同目录下的同名源文件(比如C版main.c和C++版main.cpp)会生成同名的build/main.o,很容易出现旧目标文件残留、规则匹配错乱的问题。
修复步骤
- 首先彻底清理旧构建产物,避免残留依赖干扰
直接执行命令彻底删除build目录,不要只依赖make clean(防止clean规则写漏的情况):rm -rf build - 修正源文件枚举逻辑,替换不兼容的
**通配
把Makefile里源文件定义部分改成用find做递归枚举(全POSIX环境兼容,不依赖make高版本特性),同时正确过滤不需要的C版main.c:
如果不想用find,也可以针对CubeMX的固定目录结构写明确层级的通配,效果一致:# Generated directories CORE_SOURCES := $(filter-out Core/Src/main.c,$(shell find Core -type f -name "*.c")) DRIVER_SOURCES := $(shell find Drivers/STM32WBxx_HAL_Driver -type f -name "*.c") C_SOURCES := $(CORE_SOURCES) $(DRIVER_SOURCES) # ASM sources ASM_SOURCES := startup_stm32wb55xx_cm4.s # C++ sources CXX_SOURCES := $(shell find App -type f -name "*.cpp")CORE_SOURCES := $(filter-out Core/Src/main.c,$(wildcard Core/Src/*.c)) DRIVER_SOURCES := $(wildcard Drivers/STM32WBxx_HAL_Driver/Src/*.c Drivers/STM32WBxx_HAL_Driver/Src/Legacy/*.c) CXX_SOURCES := $(wildcard App/*.cpp App/*/*.cpp) - (可选但推荐)解决同名目标文件冲突问题
如果后续可能在不同目录放同名源文件,建议把目标文件的生成规则改成保留源文件的路径层级,从根源避免同名冲突。把原来OBJECTS、vpath、编译规则、目录创建的部分替换为如下内容:
注意:Makefile中规则下的命令行必须以Tab开头,粘贴时不要替换成空格,否则会报规则错误# list of C objects OBJECTS := $(addprefix $(BUILD_DIR)/,$(C_SOURCES:.c=.o)) vpath %.c $(sort $(dir $(C_SOURCES))) # list of C++ objects OBJECTS += $(addprefix $(BUILD_DIR)/,$(CXX_SOURCES:.cpp=.o)) vpath %.cpp $(sort $(dir $(CXX_SOURCES))) # list of ASM program objects OBJECTS += $(addprefix $(BUILD_DIR)/,$(ASM_SOURCES:.s=.o)) vpath %.s $(sort $(dir $(ASM_SOURCES))) $(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) @mkdir -p $(dir $@) $(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(<:.c=.lst) $< -o $@ $(BUILD_DIR)/%.o: %.cpp Makefile | $(BUILD_DIR) @mkdir -p $(dir $@) $(CXX) -c $(CXXFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(<:.cpp=.lst) $< -o $@ $(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR) @mkdir -p $(dir $@) $(AS) -c $(CFLAGS) $< -o $@ $(BUILD_DIR): mkdir -p $@
验证方法
改完之后先执行dry run,只打印要执行的命令不实际编译,确认输出中没有编译Core/Src/main.c的步骤,只有编译App目录下main.cpp的步骤:
make -n
确认命令输出符合预期后,再正常执行make构建即可。
内容的提问来源于stack exchange,提问作者SRSR333
相关产品推荐
相关产品推荐

