每天进步一点点:Linux动态库搜索路径 & 有魔力的冒号(:)

View this thread on: d.buzz | hive.blog | peakd.com | ecency.com
·@oflyhigh·
0.000 HBD
每天进步一点点:Linux动态库搜索路径 & 有魔力的冒号(:)
还记得我将VPS从Ubuntu 18.04 LTS升级到Ubuntu 22.04 LTS导致cleos(EOS客户端)执行时找不到依赖库的问题嘛?


![image.png](https://images.hive.blog/DQmPQVkwTyjuqZgb9w6QZ7MiGRFwLS73NiNcZZiujsfsSDj/image.png)
(图源 :[pixabay](https://pixabay.com/photos/lightbulb-idea-creativity-base-3104355/))

我最终的解决方法是在Ubuntu 22.04 LTS下重新编译了EOS源码(确切地说是从新编译Leap),生产了新的cleos,一劳永逸地解决了问题。

不过今天运行另外一个项目的客户端时,发生了类似的问题,但是这个项目好久没有更新代码了,更是不支持在Ubuntu 22.04 LTS上编译,这可咋办?

# 设置动态库搜索路径

无论是重新编译项目还是降级系统都不太靠谱,那么就没办法了嘛?

其实在cleos找不到依赖库时,最初我使用的是一个折中的办法,那就是从其它主机上复制对应文件到相应的目录下,然后再执行软件。

首先用ldd查看软件的依赖:
>`ldd my_program`

响应如下:
>![image.png](https://images.hive.blog/DQmXQA79bfXvLevkNuHTtcfTU7nxnPEF1ymHC9puKvEFHkU/image.png)

从中不难看出缺少`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`:
>![1672650955923.png](https://images.hive.blog/DQmPx8QyYp8HUUYJMW81nSQUvdVkvTP1caUpkxWyzFnpEud/1672650955923.png)

如果我删除了`/home/zhangsan`下的动态库,则查找正常:
>![1672651102869.png](https://images.hive.blog/DQmaRkDaqFJZxt6bc7eeHjWKpiNNMj3w8pfT3EsbW6rws97/1672651102869.png)

也就是说,程序先查找`/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年一定要努力学习,嗯,就这么定了,我先去抖音看一会美女去,回头就去学习!

(***讲真,这些东西其实当年我上班时都会,怎么就忘得一干二净了呢?***)
👍 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,