V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
xiaopanzi
V2EX  ›  C++

关于 C/C++的共享库问题

  •  
  •   xiaopanzi · 2021-03-13 15:27:55 +08:00 · 2715 次点击
    这是一个创建于 1342 天前的主题,其中的信息可能已经有所发展或是发生改变。

    昨天读到一篇介绍共享库问题的博客,很受启发。地址: https://amir.rachum.com/blog/2016/09/17/shared-libraries/。

    文中的例子简述如下:同一目录下,有main.ccp, random.hrandom.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 条附言  ·  2021-03-13 17:07:25 +08:00
    基本破案了。谢谢各位热心大佬。
    16 条回复    2021-03-14 15:14:40 +08:00
    msg7086
        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)
    xiaopanzi
        2
    xiaopanzi  
    OP
       2021-03-13 15:47:57 +08:00
    @msg7086 那确实很有可能新版本的 g++新增了在当前路径查找 so 的功能。但我想知道如何验证这个猜想。比如: https://stackoverflow.com/questions/9922949/how-to-print-the-ldlinker-search-path 中打印搜索 lib 的目录,并没有"."。
    xiaopanzi
        3
    xiaopanzi  
    OP
       2021-03-13 15:59:56 +08:00
    哪位朋友用 g++ 9.3+试试?
    zhongrs232
        4
    zhongrs232  
       2021-03-13 16:19:37 +08:00
    @xiaopanzi Ubuntu20.04 ,gcc/g++ 9.3.0,无法复现,必须指定-Wl,-rpath=.
    thedrwu
        5
    thedrwu  
       2021-03-13 16:35:24 +08:00 via Android
    没设 relpath ?
    Jirajine
        6
    Jirajine  
       2021-03-13 16:37:54 +08:00 via Android
    这个和编译器无关吧,寻找动态库是动态链接器( ld-xxx-arch.so )干的。检查一下你的 ldconfig 。
    xiaopanzi
        7
    xiaopanzi  
    OP
       2021-03-13 16:37:57 +08:00
    @zhongrs232 奇怪了?如何解释这个相同 g++版本的不同行为?
    zhongrs232
        8
    zhongrs232  
       2021-03-13 16:39:07 +08:00
    @xiaopanzi 你是不是还设置了 LD_LIBRARY_PATH=. ?
    xiaopanzi
        9
    xiaopanzi  
    OP
       2021-03-13 16:45:32 +08:00
    @Jirajine 那个只是更新 ld.so.conf,但里面并无异常。我当前目录不在其搜索路径。
    xiaopanzi
        10
    xiaopanzi  
    OP
       2021-03-13 16:58:15 +08:00
    @zhongrs232 多谢提醒。我之前在 LD_LIBRARY_PATH 里面设置的是 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/cuda-11.2/lib64 。最后的结果就是`:/usr/local/cuda-11.2/lib64`,这个`:`有可能相当于把`.`包含进去了?
    neoblackcap
        11
    neoblackcap  
       2021-03-13 17:02:18 +08:00
    我没记错的话,好像是不同编译器的默认行为(rpath)会不一样。
    反正我都是直接指定 LD_LIBRARY_PATH,没有必要去赌这个
    xiaopanzi
        12
    xiaopanzi  
    OP
       2021-03-13 17:06:43 +08:00   ❤️ 1
    @neoblackcap 嗯。基本破案了,应该是我之前 LD_LIBRARY_PATH 中的:导致的。之前看到一些说法是 LD_LIBRARY_PATH 建议不要设置,比如: https://www.ituring.com.cn/article/22101
    neoblackcap
        13
    neoblackcap  
       2021-03-13 17:33:02 +08:00
    @xiaopanzi
    恰恰相反,LD_LIBRARY_PATH 是一个很常用的做法,Firefox 等软件都有用。你要弄一个绿色版的软件,你不指定动态库路径,别人怎么用? Stackoverflow 上面有讨论过这个问题
    wzzzx
        14
    wzzzx  
       2021-03-13 22:48:31 +08:00
    把 LD_LIBRARY_PATHd 的.取消掉再跑跑?
    codehz
        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 当前目录查找机制(造成了多少安全漏洞,尤其是在下载目录,不小心下载一个恶意动态库你一执行别的程序就直接被黑了)(这种漏洞已经被广泛利用)
    zwzmzd
        16
    zwzmzd  
       2021-03-14 15:14:40 +08:00 via Android
    env LD_DEBUG=files 启动指令

    可以看到加载 so 的过程
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5414 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 01:23 · PVG 09:23 · LAX 17:23 · JFK 20:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.