Linux 动态库踩坑:明明重新编译了 .so,调用函数返回值却一直不变(libfjrobot.so 版本号异常排查实录)
最近在写机器人 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!
- 删除系统目录里遗留的旧库
rm -f /lib/libfjrobot.so
- 把刚刚编译完成的新版库复制到系统库目录
cp ./x86-64/libfjrobot.so /lib/
再次运行 Demo,GetSDKVersion() 返回版本号和源码预期一致,问题解决。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)