在 Makefile 中实现"移除未调用函数"的功能,关键在于分别给 编译规则(生成 .o 文件时)和 链接规则(生成 .axf 文件时)添加对应的参数。
基于 ARM Compiler 5 (armcc/armlink),你需要添加的核心参数是 --split_sections(编译时)和 --remove(链接时)。
以下是具体的修改方法和完整的 Makefile 示例:
🛠️ 核心修改点
你需要修改 Makefile 中的变量定义和规则部分:
- 编译阶段 (armcc):
* 在 CFLAGS(编译选项)中加入 --split_sections。
* 作用:让每个函数都单独存放在一个独立的段中。
- 链接阶段 (armlink):
* 在 LFLAGS 或 LINKFLAGS(链接选项)中加入 --remove。
* 作用:让链接器自动剔除未被引用的段。
📝 完整的 Makefile 示例
你可以直接参考或复制以下模板,重点关注注释标记的部分:
工具链定义
CC = armcc
ARMLINK = armlink
FROMELF = fromelf
优化与编译选项配置
基础配置
CPU = --cpu=Cortex-M4
建议开启 -O2 或 -O3 优化,配合死代码消除效果更好
OPT = -O2
【关键点1】编译选项
添加 --split_sections,确保每个函数独立成段
CFLAGS = (CPU) (OPT) --split_sections -c
链接选项配置
【关键点2】链接选项
添加 --remove,指示链接器移除未使用的段
LFLAGS = --remove --scatter=scatter.sct
源文件与目标文件
SRC = main.c driver.c utils.c
OBJ = (SRC:.c=.o)
TARGET = app.axf
构建规则
all: (TARGET)
编译规则:生成 .o 文件
%.o: %.c
@echo Compiling <...
(CC) (CFLAGS) < -o @
链接规则:生成 .axf 文件
(TARGET): (OBJ)
@echo Linking...
(ARMLINK) (LFLAGS) (OBJ) -o @
可选:生成 bin 文件
(FROMELF) --bin -o (TARGET:.axf=.bin) @
清理规则
clean:
rm -f (OBJ) (TARGET) $(TARGET:.axf=.bin)
.PHONY: all clean
💡 进阶技巧:配合 LTO 获得极致优化
如果你希望进一步优化,甚至跨文件内联并消除未调用的静态函数,可以开启 链接时优化。
在 Makefile 中同时加入 -flto 标志:
在 CFLAGS 和 LFLAGS 中都加上 -flto
CFLAGS += -flto
LFLAGS += -flto
效果对比:
* 仅 --split_sections + --remove:只能移除外部可见但未调用的函数(例如你在 utils.c 写了函数但在 main.c 没用到)。
* 加上 -flto:编译器能看到整个工程的全貌,连静态 (static) 但未调用的函数也能被识别并移除,且能进行跨文件内联优化。
⚠️ 避坑指南
在使用 --remove 时,如果你的代码中使用了函数指针(例如回调函数、状态机跳转),编译器可能无法静态分析出这些函数被"调用"了,从而导致它们被误删。
解决方法:
- 使用 attribute((used)):在函数定义前加上这个属性,强制保留。
void my_callback(void) attribute((used));
void my_callback(void) { ... }
- 或者在链接器选项中强制保留:
在 LFLAGS 中添加 --keep='*.o(my_callback)'。