还记得我将VPS从Ubuntu 18.04 LTS升级到Ubuntu 22.04 LTS导致cleos(EOS客户端)执行时找不到依赖库的问题嘛?
(图源 :pixabay)
我最终的解决方法是在Ubuntu 22.04 LTS下重新编译了EOS源码(确切地说是从新编译Leap),生产了新的cleos,一劳永逸地解决了问题。
不过今天运行另外一个项目的客户端时,发生了类似的问题,但是这个项目好久没有更新代码了,更是不支持在Ubuntu 22.04 LTS上编译,这可咋办?
无论是重新编译项目还是降级系统都不太靠谱,那么就没办法了嘛?
其实在cleos找不到依赖库时,最初我使用的是一个折中的办法,那就是从其它主机上复制对应文件到相应的目录下,然后再执行软件。
首先用ldd查看软件的依赖:
ldd my_program
响应如下:
从中不难看出缺少libssl.so.1.0.0以及libcrypto.so.1.0.0,以往我的做法是从其它机器(运行18.04)或者网络上,找到这两个文件,然后复制到对应的目录,比如说: /lib/x86_64-linux-gnu/中。
但是这样做有两个问题:
- 复制时需提供root权限(否则会提示
Permission denied)- 让系统目录中有了本不该存在的内容,感觉系统被污染了
那么有没有办法,把这两个动态库直接放到软件对应的目录下,让软件执行的时候可以找到它们呢?这就要提到动态库搜索路径了。
我们可以通过以下两种方法修改动态库的搜索路径:
- 编辑
/etc/ld.so.conf,然后执行sudo ldconfig- 修改环境变量
LD_LIBRARY_PATH来指定动态库的搜索路径
很明显,第一种方法仍然需要我们提供root权限,不予考虑。那么环境变量LD_LIBRARY_PATH如何设置呢?
答案也很简单,执行诸如如下指令就可以啦:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/your/path
其中/your/path就是my_program所在的目录,比如说/home/zhangsan。
需要说明的是,这种方式只对当前登录的会话有效,重新登录后,需要重新执行上述指令。如果要经常使用,那么推荐将上述指令写入.bashrc。
通过设置 LD_LIBRARY_PATH,我们解决了软件找不到动态库的问题,但是这过程中我发现了一个有趣的事情。
回到上边提到的指令:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/zhangsan
这个指令很好理解,就是在原来的动态库搜索路径后,追加上自己的目录。其中:用来分隔不同的路径。
比如我们要程序搜索/aaa /bbb /ccc三个目录,那么这个变量最终的值,应该类似/aaa:/bbb:/ccc。
可是上述指令,我第一次执行时$LD_LIBRARY_PATH并没有被设置,所以最终$LD_LIBRARY_PATH的值为::/home/zhangsan。
虽然:看着怪怪的,但是似乎并不影响程序找到动态库。但是,真的就如此简单嘛?
我为了让程序所在目录更简洁,在相应账户下创建了一个lib目录,并将动态库复制进去一份,然后执行指令更新为:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/zhangsan/lib
echo $LD_LIBRARY_PATH显示如下内容:
:/home/zhangsan/lib
可是我执行ldd时,发现链接的竟然是/home/zhangsan/下的动态库,而不是我期望的/home/zhangsan/lib:
如果我删除了/home/zhangsan下的动态库,则查找正常:
也就是说,程序先查找/home/zhangsan/再查找/home/zhangsan/bin目录,为什么会这样呢?我陷入了深深的思索当中,我觉得之所以这样,肯定和:有关。
最终终于在man bash中的PATH条目下找到答案,其中有这样一句话:
A zero-length (null) directory name in the value of PATH indicates the current directory. A null directory name may appear as two adjacent colons, or as an initial or trailing colon.
也就是说无论是前导的:或者结尾的:或者中间连续两个:(亦即::),都代表null目录,亦即当前目录。这样,我的疑问就彻底解决啦。
所以不是冒号(:)有魔力,而是自己学习不努力呀!2023年一定要努力学习,嗯,就这么定了,我先去抖音看一会美女去,回头就去学习!
(讲真,这些东西其实当年我上班时都会,怎么就忘得一干二净了呢?)