最近在写机器人 SDK 的 Demo 程序,遇到一个非常经典的动态链接坑:Demo 调用 libfjrobot.so 里的 GetSDKVersion() 获取版本号,无论怎么修改库源码、重新编译,打印出来的版本号始终和预期不一致。

现象

我修改 SDK 源码、执行 make 重新编译生成新的 libfjrobot.so,编译日志看着一切正常,但是运行 Demo 后,GetSDKVersion() 返回的版本号一直是旧值,不会更新。

第一步排查:确认程序到底加载了哪一份 so

Linux 下程序运行时,动态链接器会按照固定的搜索顺序去找 .so 文件,并不是优先加载当前目录或者你刚刚编译出来的库。 用 ldd 命令查看 Demo 实际依赖的库路径:

ldd ./demo

我的输出:

libfjrobot.so => /lib/libfjrobot.so

问题直接定位: Demo 加载的是 /lib/libfjrobot.so,是之前拷贝到系统目录的旧版本库;我本地新编译出来的 libfjrobot.so,程序根本没有加载。 哪怕我反复编译本地源码,程序跑的依旧是老库,版本号自然不会变。

原理:Linux 动态链接搜索顺序:LD_LIBRARY_PATH → /etc/ld.so.conf 配置路径 → /lib、/usr/lib 等系统默认库目录。系统目录里同名库优先级很高,很容易抢占加载。

两种修复方案

方案 1:开发调试临时方案(推荐日常调试)

运行前设置 LD_LIBRARY_PATH,优先加载本地编译出来的库,不改动系统文件:

# 指定优先搜索本地库路径
export LD_LIBRARY_PATH=./x86-64:$LD_LIBRARY_PATH
# 校验加载路径是否切换成功
ldd ./demo
# 启动demo
./demo

新开终端需要重新执行这条环境变量命令,适合开发调试,不会污染系统。

方案 2:永久替换(我本次使用的方案,虚拟机开发环境适用)

⚠️ 注意:只适合专属开发虚拟机,生产环境不要随意操作 /lib!

  1. 删除系统目录里遗留的旧库
rm -f /lib/libfjrobot.so
  1. 把刚刚编译完成的新版库复制到系统库目录
cp ./x86-64/libfjrobot.so /lib/

再次运行 Demo,GetSDKVersion() 返回版本号和源码预期一致,问题解决。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐