笔者做过很长一段时间linux so共享库开发,开发过程中在排查so共享库报错就花了好些时间,在这里做一些分享和笔记。

比如说现在在linux上开发了一个视频流程序videoTest。
这个videoTest需要依赖libDealVideo.so的驱动共享库,本来编译正常,但是放到实际环境中就起不来了。

一、报错提示version `GLIBC_3.12' not found。

1、问题复现:

我的编译环境是linux ubuntu20.04,但是实际运行环境是linux fedora8。
在linux ubuntu20.04运行没问题,但是在linux fedora8运行就会报这个错。

2、问题排错:

排查思路为当前GLIBC_3.12是一个函数符号,那就找找 libDealVideo.so没有这个符号,用strings可以编译匹配查询当前文件中,我们想找的字符串。

这个时候你用指令”strings libDealVideo.so | grep GLIBC“。
在linux ubuntu20.04上执行:

在linux fedora8上执行:

3、原因分析:

什么是跨设备编译呢?就像问题复现说编译环境是linux ubuntu20.04,但是实际运行环境是linux fedora8。
进一步分析linux ubuntu20.04中的glibc库有GLIBC_3.12版本,但是linux fedora8没有GLIBC_3.12版本,所以会有这个问题。

4、问题处理:

(1)方案一:自行安装一个linux fedora8虚拟机再安装gcc/g++编译libDealVideo.so和videoTest,不要用linux ubuntu20.04
(2)方案二:直接在运行环境linux fedora8上安装gcc/g++编译libDealVideo.so和videoTest,不要用linux ubuntu20.04
(3)方案三:直接在运行环境linux fedora8更新glibc库到GLIBC_3.12版本,但是这个不建议使用,因为可能会影响到运行环境中其他程序。

二、报错提示so共享库找不到libDealVideo.so not found

1、问题复现:

我把编译好的libDealVideo.so和videoTest放置到运行环境/home/test目录下,然后执行videoTest报错,报错提示为libDealVideo.so not found。

2、问题排错:

排查思路为当前是找不到库,在linux查看程序依赖库可以用ldd指令。
在当前运行环境上执行:

3、问题分析:

可以看得到当前libDealVideo.so和videoTest虽然都在同一个目录,但是实际上videoTest确实找不到对应依赖库libDealVideo.so。

那这种情况一般是因为libDealVideo.so没有在环境变量中,videoTest在环境变量配置中的路径中遍历文件没找到libDealVideo.so。

4、问题处理:

(1)方案一:临时处理,配置LD_LIBRARY_PATH环境变量,这样做有个好处就是这个变量仅仅用于当前窗口终端,不会影响到环境里面其他终端。设置当前/home/test目录为环境变量,具体方法为:

$PWD表示当前目录,$PATH是之前就已经配置的环境变量。如果要临时处理,可不加之前配置好的环境变量。具体方法为:

同时验证当前临时配置指令是否生效可以下方法验证:

(2)方案二:临时处理,直接把libVideoTest.so放置到/lib64或者/usr/lib64这些系统默认目录。
这里放lib64还是lib,主要是看当前系统是64位还是32位的。

(3)方案三:长期处理,在/etc/ld.so.conf.d/中添加新的conf文件。
比如说新增一个videoTest的路径依赖配置,命名为videoTest.conf,把/home/test添加进去

sudo ldconfig是为了让新增的videoTest.conf立即生效。

三、跑着跑着程序崩了

1、内存泄露或者内存访问越界--gdb复现

这种情况,一般推荐用gdb复现一下,用gdb复现崩溃现象后,在gdb中输入bt,查看更具体的报错信息。
如果没gdb条件的,那就保留coredump信息。
有时候可能so库是同事A开发的,应用是B同事开发的,为了避免扯皮还有高效排错,还是gdb查看更具体的信息更好。

2、内存泄露或者内存访问越界--Valgrind内存检测工具

3、so库版本过旧,缺少函数

随着版本迭代,so库可能会新增一些功能函数。但是在调试时候,可能会不小心用了旧的so库,导致跑着跑着就崩了,这种情况也比较难排查。

(1)建议在so库中用printf打印出版本号。

这样有什么好处呢?
假如现在版本为so库MY1.3.0
如果你当初定义一个版本号但是没打印,用strings指令是搜不出来的。
但是如果加上printf打印出版本号,用strings指令是可以搜出来的。

(2)另外就是用软链接的方式。

每一个so版本都加载版本号后缀,再用软链接的方式链接起来。

02-06 12:26