昨天读到一篇介绍共享库问题的博客,很受启发。地址: https://amir.rachum.com/blog/2016/09/17/shared-libraries/。
文中的例子简述如下:同一目录下,有main.ccp
, random.h
和random.cpp
,将random.cpp
打包成 so 文件,再让main.cpp
和该 so 文件链接得到可执行文件main
。
但是有个疑问,在该博客中通过clang++ -o main main.o -lrandom -L.
之后,无法直接运行该可执行文件,报的错误是:
/main: error while loading shared libraries: librandom.so: cannot open shared object file: No such file or directory
但是经过我测试(分别在 Ubuntu 下的 g++ 9.3 和 Mac OS 下的 clang++ 12.0),我可以直接运行该可执行文件,通过ldd
命令也可看出 librandom.so 文件是能够被找到的。
linux-vdso.so.1 (0x00007ffe279d2000) librandom.so (0x00007f7776fca000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f7776dcd000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7776bdb000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f7776a8c000) /lib64/ld-linux-x86-64.so.2 (0x00007f7776fd6000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f7776a71000)
那是不是意味着,从某个版本开始,g++/clang++能够自动查找当前目录下的 so 文件?如果是,如何确认 g++/clang++的可搜索的路径包括当前目前(即.
)?
1
msg7086 2021-03-13 15:40:32 +08:00
g++ 8.3 无法复现。
# ldd main linux-vdso.so.1 (0x00007ffe86d29000) librandom.so => not found libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f6aeaa49000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f6aea8c6000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f6aea8ac000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6aea6eb000) /lib64/ld-linux-x86-64.so.2 (0x00007f6aeabe3000) |
2
xiaopanzi OP @msg7086 那确实很有可能新版本的 g++新增了在当前路径查找 so 的功能。但我想知道如何验证这个猜想。比如: https://stackoverflow.com/questions/9922949/how-to-print-the-ldlinker-search-path 中打印搜索 lib 的目录,并没有"."。
|
3
xiaopanzi OP 哪位朋友用 g++ 9.3+试试?
|
4
zhongrs232 2021-03-13 16:19:37 +08:00
@xiaopanzi Ubuntu20.04 ,gcc/g++ 9.3.0,无法复现,必须指定-Wl,-rpath=.
|
5
thedrwu 2021-03-13 16:35:24 +08:00 via Android
没设 relpath ?
|
6
Jirajine 2021-03-13 16:37:54 +08:00 via Android
这个和编译器无关吧,寻找动态库是动态链接器( ld-xxx-arch.so )干的。检查一下你的 ldconfig 。
|
7
xiaopanzi OP @zhongrs232 奇怪了?如何解释这个相同 g++版本的不同行为?
|
8
zhongrs232 2021-03-13 16:39:07 +08:00
@xiaopanzi 你是不是还设置了 LD_LIBRARY_PATH=. ?
|
10
xiaopanzi OP @zhongrs232 多谢提醒。我之前在 LD_LIBRARY_PATH 里面设置的是 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/cuda-11.2/lib64 。最后的结果就是`:/usr/local/cuda-11.2/lib64`,这个`:`有可能相当于把`.`包含进去了?
|
11
neoblackcap 2021-03-13 17:02:18 +08:00
我没记错的话,好像是不同编译器的默认行为(rpath)会不一样。
反正我都是直接指定 LD_LIBRARY_PATH,没有必要去赌这个 |
12
xiaopanzi OP @neoblackcap 嗯。基本破案了,应该是我之前 LD_LIBRARY_PATH 中的:导致的。之前看到一些说法是 LD_LIBRARY_PATH 建议不要设置,比如: https://www.ituring.com.cn/article/22101
|
13
neoblackcap 2021-03-13 17:33:02 +08:00
@xiaopanzi
恰恰相反,LD_LIBRARY_PATH 是一个很常用的做法,Firefox 等软件都有用。你要弄一个绿色版的软件,你不指定动态库路径,别人怎么用? Stackoverflow 上面有讨论过这个问题 |
14
wzzzx 2021-03-13 22:48:31 +08:00
把 LD_LIBRARY_PATHd 的.取消掉再跑跑?
|
15
codehz 2021-03-14 05:25:35 +08:00
@neoblackcap 并不常见,这个用法多数是一种 hack,而且一定要严格限定范围,最好直接只针对特定 desktop 文件。。全局设置肯定炸。。。
绿色版软件这种说法,在 linux 下就很奇怪,因为除了动态库本身之外还有很多因素会干掉你的兼容性(比如 glibc 版本),分发的时候一般都是采用 1. 打包成 deb,rpm,2. 使用 snap,flathub,appimage 等容器机制 (而且非要 hack 也推荐直接用 rpath 加 $ORIGIN 特殊关键字来实现(见 nix patchelf )不方便改二进制的时候才会考虑使用环境变量。) 环境变量会继承,设置成这种相当于自己引入 windows 想改改不掉的 dll 当前目录查找机制(造成了多少安全漏洞,尤其是在下载目录,不小心下载一个恶意动态库你一执行别的程序就直接被黑了)(这种漏洞已经被广泛利用) |
16
zwzmzd 2021-03-14 15:14:40 +08:00 via Android
env LD_DEBUG=files 启动指令
可以看到加载 so 的过程 |