结论是链接阶段符号多重定义,根源在于头文件中定义了变量或函数体,应改用extern声明变量、函数体移至.c文件或加inline,结构体/枚举/宏无影响;gcc 10+禁用-fcommon导致老项目编译失败,可临时加-fcommon或升级/打补丁;静态库重复链接需检查makefile;定位用nm -c。

直接说结论:这不是代码写错了,是链接阶段发现同一个符号在多个 .o 文件里被定义了,必须让每个符号只在一个地方定义。
头文件里写了变量或函数体?立刻改掉
这是最常见也最容易被忽略的根源。比如在 config.h 里写了 int debug_flag = 0; 或 void log_init() { ... },只要两个 .c 文件都 #include "config.h",链接时就必然报 multiple definition of 'debug_flag'。
- 变量必须用
extern声明(头文件),真正在某个.c文件里定义一次 - 函数体不能放在头文件里;要么移到
.c文件,要么加inline(仅限简单函数) - 结构体、枚举、宏定义不受影响,它们只是声明,不占内存
GCC 10+ 默认禁用 -fcommon,老内核/工具链会崩
Linux 4.15、U-Boot 2020.01 等老项目在 GCC 10.3+ 下编译常卡在 yylloc 或 yytext 多重定义,错误信息里明确指向 dtc-lexer.lex.o 和 dtc-parser.tab.o —— 这不是你写的代码问题,是 Flex/Bison 生成的代码依赖旧版 GCC 的 -fcommon 行为。
- 临时解法:加编译选项
-fcommon,例如在Makefile中追加CFLAGS += -fcommon - 长期解法:升级内核或 DTC 子模块,或打补丁(如修改
dtc-lexer.lex.c_shipped,把yylloc改成static或加extern声明) - 注意:
-fcommon在 GCC 12+ 已彻底移除,不能当永久方案
静态库或目标文件被重复链接
错误信息里如果出现类似 libxxx.a(file1.o): multiple definition of 'xxx' 和 libxxx.a(file2.o): first defined here,说明同一个静态库被链接了两次,或者两个不同静态库提供了同名符号。
- 检查
Makefile或CMakeLists.txt,确认没有重复写-lxxx或多次add_library - 用
nm -C libxxx.a | grep 'xxx'查看哪个.o文件真定义了该符号 - 交叉编译时尤其注意:某些 SDK 会把驱动和中间件打包进多个
.a,需手动剔除冗余
真正麻烦的不是报错本身,而是它可能藏在第三方子模块里 —— 比如 DTC、libfdt、甚至某个 C++ 模板实例化泄漏到全局符号表。遇到时别急着改自己代码,先用 nm -C *.o | grep 'symbol_name' 锁定定义位置,再决定是加 static、改声明方式,还是绕过那个模块。











