最近在写机器人 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() 返回版本号和源码预期一致,问题解决。