STM32MP157-M4:Makefile 完整逐段详解

【高危前置提醒】必须开启 --gc-sections 死代码回收避免 SRAM 溢出;编译参数必须携带 -DCORE_CM4os_config/ 必须在 -I 列表首行。

0 前言

纯 GNU Make 构建工程,不依赖任何 IDE。Makefile 自动遍历源码目录(支持递归子文件夹)、区分大小写汇编文件(.s vs .S),一键生成 .elf / .bin / .hex / .map 文件,并且内置 make flash 一键 OpenOCD 烧录。

在这里插入图片描述

1 工具链基础定义

CROSS_COMPILE ?= arm-none-eabi-
CC       := $(CROSS_COMPILE)gcc
AS       := $(CROSS_COMPILE)gcc -x assembler-with-cpp
LD       := $(CROSS_COMPILE)gcc
OBJCOPY  := $(CROSS_COMPILE)objcopy
OBJDUMP  := $(CROSS_COMPILE)objdump
SIZE     := $(CROSS_COMPILE)size

TARGET   := m4_liteos
PROJ_ROOT := .
BUILD_DIR := build

关键设计:

  • AS 重用 gcc 而非 as:带预处理器的汇编(.S 后缀)需要经过 C 预处理
  • PROJ_ROOT 设为 .:Makefile 和工程根目录同层,所有路径相对引用

2 核心编译参数

# CPU 浮点配置(M4 + 硬浮点 + FPv4-SP-D16)
CPUFLAGS := -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16

# 芯片宏(CORE_CM4 必须!缺失会导致 HAL/CMSIS 丢失 M4 相关定义)
CHIP_DEFS := -DSTM32MP157Cxx -DSTM32MP1 -DCORE_CM4

# LiteOS 场景宏
LITEOS_DEFS := -DLOSCFG_LIB_CONFIG="-los_builddef.h"

# C 编译标志(-Os 空间优化 + debug 符号 + 段分离用于 gc-sections)
CFLAGS  := $(CPUFLAGS) $(CHIP_DEFS) $(LITEOS_DEFS) $(INCLUDES)
CFLAGS  += -Wall -Wextra -g3 -Os
CFLAGS  += -ffunction-sections -fdata-sections     # 每个函数/变量独立一个段
CFLAGS  += -fno-common -fmessage-length=0
CFLAGS  += --specs=nano.specs                      # 使用 newlib-nano 减小体积

# 汇编标志
ASFLAGS := $(CPUFLAGS) $(CHIP_DEFS) $(INCLUDES)

# 链接标志
LDFLAGS  := $(CPUFLAGS) -T$(PROJ_ROOT)/stm32mp157_m4.lds
LDFLAGS  += -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref   # 生成完整 map
LDFLAGS  += -Wl,--gc-sections                              # 死代码回收
LDFLAGS  += --specs=nano.specs -lnosys                    # nano 库+无系统调用

--gc-sections 的作用:编译器把每个函数 / 全局变量放进独立段(-ffunction-sections -fdata-sections),链接时未被引用的段自动丢弃。开启前固件可能超过 SRAM 上限,开启后省下几十 KB。

3 源文件收集规则

# ========== 汇编源文件(手动指定,避免 wildcard 漏抓 ==========
ASM_SRC += Core/Startup/startup_stm32mp15xx.s       # 启动文件(纯汇编 .s)
ASM_SRC += kernel_liteos_m/kernel/arch/arm/cortex-m4/gcc/los_dispatch.S
ASM_SRC += kernel_liteos_m/kernel/arch/arm/cortex-m4/gcc/los_exc.S

# ========== HAL 驱动(过滤 ll_ 文件)==========
HAL_SRC  := $(filter-out %ll_%, $(wildcard Drivers/STM32MP1xx_HAL_Driver/Src/*.c))

# ========== LiteOS 内核 C 源码 ==========
LITEOS_SRC := $(wildcard kernel_liteos_m/kernel/src/*.c)
LITEOS_SRC += $(wildcard kernel_liteos_m/kernel/arch/arm/cortex-m4/gcc/*.c)

# ========== 用户应用 C 源码 ==========
APP_SRC := $(wildcard Core/Src/*.c)
APP_SRC += $(wildcard Drivers/BSP/**/*.c)
APP_SRC += $(wildcard Drivers/SYSTEM/**/*.c)

注意:GNU Make 的 wildcard 不支持 ** 递归通配符。深层子目录需要分层单独写 wildcard,或使用 foreach + shell find 组合。

4 编译规则(大小写汇编分开)

# C 文件编译
$(BUILD_DIR)/%.o: %.c
    @mkdir -p $(dir $@)
    $(CC) -c $(CFLAGS) -MMD -MP $< -o $@

# 大写 .S 汇编(含预处理,需要传递 INCLUDES)
$(BUILD_DIR)/%.o: %.S
    @mkdir -p $(dir $@)
    $(AS) -c $(ASFLAGS) $< -o $@

# 小写 .s 纯汇编(无预处理)
$(BUILD_DIR)/%.o: %.s
    @mkdir -p $(dir $@)
    $(CC) -c $(CPUFLAGS) $< -o $@

大写 .S 和小写 .s 必须分开.S 文件含 C 宏和 #include,必须经过 C 预处理(-x assembler-with-cpp),并且需要 -I 头文件路径;.s 是纯汇编,直接汇编即可。

5 链接与产物生成

$(BUILD_DIR)/$(TARGET).elf: $(OBJS)
    @echo "Linking $(BUILD_DIR)/$(TARGET).elf..."
    $(LD) $(OBJS) $(LDFLAGS) -o $@
    @echo "  BUILD SUCCESS: $(TARGET).elf"

$(BUILD_DIR)/$(TARGET).bin: $(BUILD_DIR)/$(TARGET).elf
    $(OBJCOPY) -O binary $< $@

$(BUILD_DIR)/$(TARGET).hex: $(BUILD_DIR)/$(TARGET).elf
    $(OBJCOPY) -O ihex $< $@

6 内置命令一览

命令功能
make完整编译,生成 elf/bin/hex
make clean清空 build 目录
make flash调用 OpenOCD 自动下载并运行(需 OpenOCD 已安装)
make info打印源码数量、工具链版本、固件大小

7 flash 目标:OpenOCD 一键烧录

OPENOCD      ?= D:/tools/xpack-openocd-0.12.0-5-win32-x64/xpack-openocd-0.12.0-5/bin/openocd.exe
OCD_SCRIPTS  ?= D:/tools/xpack-openocd-0.12.0-5-win32-x64/xpack-openocd-0.12.0-5/openocd/scripts

# 从 elf 动态取 Reset_Handler 符号地址,避免硬编码
ENTRY  = $(shell $(OBJDUMP) -t $(BUILD_DIR)/$(TARGET).elf | grep " Reset_Handler" | awk '$$2!=""{print "0x"$$1}')
READELF = $(CROSS_COMPILE)readelf

flash: all
    "$(OPENOCD)" -s "$(OCD_SCRIPTS)" \
      -f openocd/board_stm32mp157_m4.cfg \
      -c "init" -c "targets stm32mp15x.cm4" -c "halt" \
      -c "load_image $(BUILD_DIR)/$(TARGET).elf" \
      -c "reg pc $(ENTRY)" \
      -c "resume" -c "shutdown"

关键设计ENTRY 从 elf 符号表动态解析 Reset_Handler 地址,永不硬编码。每次 make 后入口地址可能因代码量变化而漂移,硬编码必翻车。


⚠️ 本节踩坑速览

现象根因修复
wildcard 无法递归遍历内核多层文件夹GNU Make 不支持 **分层单独写 wildcard 子目录
大写 .S 汇编头文件找不到误用小写 .s 编译规则分开编写 .s.S 两套规则
编译后固件过大、SRAM 溢出未开启 --gc-sectionsCFLAGS + LDFLAGS 成对添加
大量 GPIO / UINT32 未定义缺失 -DCORE_CM4CHIP_DEFS 添加 -DCORE_CM4
printf 打印浮点数运行崩溃未链接 nano 浮点库LDFLAGS 增加 -u _printf_float
make flash PC 地址错误硬编码 Reset_Handler 地址改用 elf 符号表动态解析
编译 memcpy/memset 等函数未定义--specs=nano.specs 依赖 newlib-nano确认工具链已安装 newlib-nano
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐