嵌入式项目Makefile越写越乱?一张万能模板+5个技巧,告别重复劳动 📅 2026/7/15 12:50:17 嵌入式项目Makefile越写越乱一张万能模板5个技巧告别重复劳动在嵌入式开发里待久了你会发现一个规律项目越做越大Makefile越来越屎。刚开始就两三源文件一个Makefile十行搞定。等到外设驱动、协议栈、第三方库、不同硬件版本、不同编译选项全混进来Makefile膨胀到三四百行改个选项要翻半天换个芯片平台直接重写——更别提新人接手后那副生无可恋的表情。今天我给你一个模板以及几个我觉得最有用的Makefile技巧。模板直接拿走改改就能用。一个通用嵌入式项目的Makefile模板这个模板我用了好几年跨了三个芯片平台、几十个项目。核心思路就一条区分平台相关和项目相关的配置。# # 嵌入式项目通用Makefile模板 v2.0 # 适用场景MCU裸机 / FreeRTOS / 轻量级Linux应用 # # --- 平台配置换芯片改这里就行--- CROSS_COMPILE ? arm-none-eabi- CC : $(CROSS_COMPILE)gcc LD : $(CROSS_COMPILE)ld AS : $(CROSS_COMPILE)as OBJCOPY : $(CROSS_COMPILE)objcopy SIZE : $(CROSS_COMPILE)size # 芯片型号和链接脚本 MCU ? STM32F407 LINKER_SCRIPT ? stm32f407_flash.ld # 架构相关标志 ARCH_FLAGS : -mcpucortex-m4 -mthumb -mfloat-abihard -mfpufpv4-sp-d16 # --- 项目配置换项目改这里--- TARGET ? firmware PROJ_DIR : . SRC_DIRS : src INC_DIRS : inc lib/inc LIB_DIRS : lib # 源文件收集 SRCS : $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) SRCS $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.s)) OBJS : $(SRCS:.c.o) OBJS : $(OBJS:.s.o) # 编译标志 CFLAGS : $(ARCH_FLAGS) -Wall -Wextra -Werror -O2 -g3 CFLAGS $(addprefix -I,$(INC_DIRS)) -D$(MCU) LDFLAGS : $(ARCH_FLAGS) -T$(LINKER_SCRIPT) -Wl,--gc-sections LDFLAGS $(addprefix -L,$(LIB_DIRS)) # --- 构建目标 --- .PHONY: all clean flash size all: $(TARGET).bin $(TARGET).hex # 链接 $(TARGET).elf: $(OBJS) $(CC) $^ -o $ $(LDFLAGS) $(SIZE) $ # 转二进制烧录用 %.bin: %.elf $(OBJCOPY) -O binary $ $ %.hex: %.elf $(OBJCOPY) -O ihex $ $ # 编译 %.o: %.c $(CC) $(CFLAGS) -c $ -o $ %.o: %.s $(AS) $(ARCH_FLAGS) -c $ -o $ # 烧录通过OpenOCD flash: $(TARGET).bin openocd -f board/stm32f4discovery.cfg \ -c program $(TARGET).bin 0x08000000 verify reset exit # 清理 clean: rm -f $(OBJS) $(TARGET).elf $(TARGET).bin $(TARGET).hex # 查看固件大小 size: $(TARGET).elf $(SIZE) $(TARGET).elf怎么用这个模板换芯片改CROSS_COMPILE、MCU、ARCH_FLAGS、LINKER_SCRIPT加源文件目录往SRC_DIRS加一行加头文件目录往INC_DIRS加一行核心原则平台相关扔上面项目相关扔下面。换平台不用动构建逻辑换项目不用动编译参数。只改A层只改B层模板分层平台配置层交叉编译器架构标志链接脚本项目配置层源文件路径头文件路径目标名称构建规则层编译规则链接规则格式转换烧录命令换平台5分钟适配换项目改改路径就行技巧一自动依赖管理——别再手动clean了嵌入式工程师最常干的蠢事包括曾经的我改了一个头文件忘记make clean烧进去发现没生效排查半天。其实Makefile支持自动追踪头文件依赖。加三行就行# 在模板基础上加这三段 # 1. 生成.d依赖文件 DEP_DIR : .dep $(shell mkdir -p $(DEP_DIR)) # 2. 编译时同时生成依赖文件 %.o: %.c $(CC) $(CFLAGS) -MMD -MF $(DEP_DIR)/$*.d -c $ -o $ # 3. 包含生成的依赖文件 -include $(wildcard $(DEP_DIR)/*.d) # 4. clean时一起删掉 clean: rm -f $(OBJS) $(TARGET).elf $(TARGET).bin $(TARGET).hex rm -rf $(DEP_DIR)加完后你改了头文件受影响的所有.c文件会被自动重新编译。不需要手动clean不需要记依赖关系。技巧二多配置构建——Debug/Release/Prod一个项目经常需要在Debug和Release配置间切换。别搞两个Makefile用一个# 构建配置 BUILD ? release ifeq ($(BUILD),debug) CFLAGS -Og -DDEBUG -DLOG_LEVELLOG_DEBUG LDFLAGS -u _printf_float # 开启浮点printf栈大一点 else ifeq ($(BUILD),prod) CFLAGS -Os -DNDEBUG -DLOG_LEVELLOG_ERROR LDFLAGS --print-memory-usage else CFLAGS -O2 -DNDEBUG -DLOG_LEVELLOG_WARN endif # 不同构建的输出目录隔离 BUILD_DIR : build/$(BUILD) OBJS : $(addprefix $(BUILD_DIR)/,$(SRCS:.c.o)) # 使用示例 # make BUILDdebug # make BUILDrelease # make BUILDprod技巧三支持多芯片变体一个项目可能出几个硬件版本比如STM32F407和STM32F429两个版本。不要复制Makefile# 通过MCU变量控制所有差异 ifeq ($(MCU),STM32F407) ARCH_FLAGS : -mcpucortex-m4 -mthumb -mfloat-abihard -mfpufpv4-sp-d16 LINKER_SCRIPT : stm32f407_flash.ld CFLAGS -DSTM32F407 else ifeq ($(MCU),STM32F429) ARCH_FLAGS : -mcpucortex-m4 -mthumb -mfloat-abihard -mfpufpv4-sp-d16 LINKER_SCRIPT : stm32f429_flash.ld CFLAGS -DSTM32F429 -DUSE_LCD SRC_DIRS lcd_driver # F429有LCD加驱动目录 endif # 使用 # make MCUSTM32F407 # make MCUSTM32F429 BUILDdebug技巧四条件编译不污染代码条件编译用#ifdef多了代码可读性会急剧下降。一个更好的方式用Makefile控制编译哪些文件。假设你有NAND Flash驱动和NOR Flash驱动不同版本用不同的ifeq ($(FLASH_TYPE),nand) SRC_DIRS drivers/nand CFLAGS -DFLASH_TYPE_NAND else SRC_DIRS drivers/nor CFLAGS -DFLASH_TYPE_NOR endif # make FLASH_TYPEnand # make FLASH_TYPEnor这样代码里不需要#ifdef FLASH_TYPE_NAND之类的东西两个驱动文件完全独立阅读和维护都清爽。技巧五自动化代码检查——编译完直接跑检查在编译流程里内置静态检查省得后面单独跑# 编译完成后自动检查 all: check $(TARGET).bin # 静态代码检查 check: $(SRCS) echo 运行静态检查 cppcheck --enablewarning,style --error-exitcode1 \ $(addprefix -I,$(INC_DIRS)) $(SRCS) echo 检查通过 # 代码格式检查可选 format-check: clang-format --dry-run --Werror $(SRCS) # 圈复杂度统计 complexity: pmccabe $(SRCS) | sort -rn | head -20把这些加到all的依赖里每次编译自动触发比放到CI流程里反馈快得多。git commitmake编译静态检查格式检查链接生成binmake flash烧录总结一个好的Makefile应该让你忘记它的存在。它应该自动处理依赖、自动区分配置、自动适配平台。如果你还在手动clean、手动改路径、手动区分Debug和Release——说明你的Makefile该升级了。把模板拿走把五个技巧加到你的项目里以后每次编译你都会感谢现在的自己。课后作业你的项目Makefile里有没有make clean的需求如果有说明依赖管理没做好你的项目有几个硬件版本是不是靠复制Makefile来管理的试试把上面的自动依赖管理加到现有项目里——改一个头文件看会不会自动触发重编