You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Makefile编译C程序时出现undefined reference错误,求排查方案

编译链接错误排查:未定义引用问题

问题场景

当前Makefile内容

gcc -c -fPIC ./command/cd.c -o ./command/cd.o
gcc -c -fPIC ./command/exit.c -o ./command/exit.o
gcc -c -fPIC ./command/pwd.c -o ./command/pwd.o
gcc -shared ./command/*.o -o ./commands.o

gcc -fPIC -c -o utils/command.o utils/command.c
gcc -fPIC -c -o utils/lineParser.o utils/lineParser.c
gcc -fPIC -c -o utils/memory.o utils/memory.c
gcc -fPIC -c -o utils/printing.o utils/printing.c
gcc -shared ./utils/*.o -o ./utils.o

gcc -c -fPIC ./runner.c -o ./runner.o
gcc -shared utils.o commands.o runner.o -o app.o -lreadline

gcc app.o -o slash

报错信息

app.o: undefined reference to `Malloc'
app.o: undefined reference to `exitCommandRunner' 
app.o: undefined reference to `pwdCommandRunner'
[...]

相关函数位置

  • Malloc:声明于utils/memory.h,实现于utils/memory.c
  • exitCommandRunner:声明于command/exit.h,实现于command/exit.c
  • pwdCommandRunner:声明于command/pwd.h,实现于command/pwd.c

头文件包含情况

runner.c中已包含对应头文件:

#include "runner.h"
#include "./utils/memory.h"
#include "./utils/command.h"
#include "./utils/lineParser.h"
#include "./utils/printing.h"
#include "./command/cd.h"
#include "./command/pwd.h"
#include "./command/exit.h"

问题原因

  1. 共享库依赖处理错误:你将app.o编译为共享库(使用-shared参数),但共享库不会打包依赖的utils.o、commands.o中的符号,仅记录依赖关系。后续直接用gcc app.o -o slash链接可执行文件时,未提供这些依赖库,导致链接器找不到对应符号。
  2. 链接顺序不符合规则:Linux链接器遵循「引用者在前,被引用者在后」的顺序,你在生成app.o时将依赖库放在了引用者(runner.o)前面,可能导致部分符号无法被正确解析。
  3. 不必要的中间共享库:小型项目中生成多个中间共享库反而增加复杂度,直接使用目标文件链接更稳妥。

修复方案

方案1:直接用目标文件链接(推荐)

修改Makefile,跳过中间共享库生成,直接将所有目标文件按正确顺序链接成可执行文件:

# 编译命令模块目标文件
gcc -c -fPIC ./command/cd.c -o ./command/cd.o
gcc -c -fPIC ./command/exit.c -o ./command/exit.o
gcc -c -fPIC ./command/pwd.c -o ./command/pwd.o

# 编译工具模块目标文件
gcc -fPIC -c -o utils/command.o utils/command.c
gcc -fPIC -c -o utils/lineParser.o utils/lineParser.c
gcc -fPIC -c -o utils/memory.o utils/memory.c
gcc -fPIC -c -o utils/printing.o utils/printing.c

# 编译runner模块
gcc -c -fPIC ./runner.c -o ./runner.o

# 链接所有目标文件生成可执行文件,顺序:引用者在前,依赖在后
gcc ./runner.o ./command/*.o ./utils/*.o -o slash -lreadline

方案2:保留共享库(适合大型项目)

如果坚持使用共享库,需要遵循共享库命名规范,并在链接时显式指定依赖:

# 编译命令模块并生成标准命名的共享库
gcc -c -fPIC ./command/cd.c -o ./command/cd.o
gcc -c -fPIC ./command/exit.c -o ./command/exit.o
gcc -c -fPIC ./command/pwd.c -o ./command/pwd.o
gcc -shared ./command/*.o -o libcommands.so

# 编译工具模块并生成标准命名的共享库
gcc -fPIC -c -o utils/command.o utils/command.c
gcc -fPIC -c -o utils/lineParser.o utils/lineParser.c
gcc -fPIC -c -o utils/memory.o utils/memory.c
gcc -fPIC -c -o utils/printing.o utils/printing.c
gcc -shared ./utils/*.o -o libutils.so

# 编译runner模块
gcc -c -fPIC ./runner.c -o ./runner.o

# 生成可执行文件,显式指定依赖的共享库
gcc ./runner.o -o slash -L. -lcommands -lutils -lreadline

注:-L.表示在当前目录查找共享库,-lcommands对应libcommands.so,-lutils对应libutils.so。

额外检查点

  • 确认所有被引用的函数(如Malloc、exitCommandRunner)没有被static修饰,static会限制函数作用域为当前文件,外部无法访问。
  • 核对头文件中的函数声明与.c文件中的实现完全一致,包括参数类型、数量和返回值类型。

内容的提问来源于stack exchange,提问作者Akihiro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 01:50:33