gcc link 共享库在指定路径但不在标准路径

gcc link the shared library in specified path but not in the standard path

我在使用 gcc link 指定路径但不在标准路径中的共享库时遇到了一个奇怪的问题。

当我下载GNU readline library version 6.3并在路径$HOME/Downloads.

编译成功

GNU readline 库需要 link libtinfo,所以我通过 sudo apt-get install libtinfo.

安装了它

之后,我创建了一个名为rl.c的小样本测试来检查它。为了构建示例项目,我还创建了两个符号 links,如下所示:

$ ls -lrt ~/Downloads/
drwxr-xr-x 6 sfzhang sfzhang    4096 Mar  2 15:45 readline-6.3
lrwxrwxrwx 1 sfzhang sfzhang      12 Mar  2 16:00 readline -> readline-6.3

$ ls -lrt ~/Downloads/readline-6.3/shlib/
-rwxr-xr-x 1 sfzhang sfzhang 833856 Mar  2 15:36 libreadline.so.6.3
lrwxrwxrwx 1 sfzhang sfzhang     18 Mar  2 16:28 libreadline.so -> libreadline.so.6.3

为了使用新构建的 readline 库,我将路径导出到 LD_LIBRARY_PATH:

$ echo $LD_LIBRARY_PATH
/home/sfzhang/Downloads/readline/shlib

并且,我使用以下命令编译了 rl.c

$ gcc -o rl rl.c -I$HOME/Downloads -L$HOME/Downloads/readline/shlib -lreadline -ltinfo

检查 rl linked 库:

$ ldd rl
linux-vdso.so.1 =>  (0x00007fffe09a3000)
libreadline.so.6 => /lib/x86_64-linux-gnu/libreadline.so.6 (0x00007fe22d243000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007fe22d01a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe22cc8d000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe22d492000)

我也尝试了另一个命令,但得到了相同的结果:

gcc -o rl rl.c -I$HOME/Downloads -L$HOME/Downloads/readline/shlib -lreadline -ltinfo -Wl,-rpath,$HOME/Downloads/readline/shlib

所以,为什么 rl 被喜欢 /lib/x86_64-linux-gnu/libreadline.so.6 而不是 $ HOME/Downloads/readline/shlib/libreadline.so.

OS: Linux debian 3.2.0-4-amd64 #1 SMP Debian 3.2.65-1+deb7u1 x86_64 GNU/Linux

gcc:gcc 版本 4.7.2 (Debian 4.7.2-5)

ldd: ldd (Debian EGLIBC 2.13-38+deb7u6) 2.13

您还需要一个名为 libreadline.so.6 的符号 link,而不仅仅是 libreadline.so。原因是libreadline.so.6.3sonamelibreadline.so.6.

A soname 是嵌入在库本身中的 "generic" 名称。当您 link 针对具有 soname 的共享库时,它是嵌入到您的可执行文件中并随后由动态 linker 查找的名称。 (对于没有 sonames 的共享库,使用文件名代替,尽管这并不常见。)您可以通过 运行 来判断库的 soname 是什么,例如

objdump -p <library> | grep SONAME

sonames 的目的是使您的可执行文件 link 与应该兼容的最通用的库名称(通常是仅带有 主要版本 -- 在这种情况下为 6 -- 添加),而不仅仅是您碰巧 link 反对的特定(例如,小错误修复版本)版本。

ldd 的输出还告诉您它正在专门寻找 libreadline.so.6

解决问题的替代方法有:

  1. Link 反对 .so 的完整路径。例如

    $ gcc -o rl rl.c -I$HOME/Downloads $HOME/Downloads/readline/shlib/readline.so.6.3 -ltinfo
    

    正如@Ulfalizer 所建议的,您可能需要另一个仅包含主要编号的符号 link。

  2. 如果您正在使用 LD_LIBRARY_PATH,请不要忘记将其导出。

  3. 在使用-L<path>时也使用-Wl,-rpath,<path>,这样运行时linker ld.so.2在与[=相同的路径下找到共享库17=] 确实如此,例如:

    $ gcc -o rl rl.c -I$HOME/Downloads -L$HOME/Downloads/readline/shlib -Wl,-rpath,$HOME/Downloads/readline/shlib -lreadline -ltinfo
    

在调试 linker 问题时,使用 readelf -d <binary> 命令查看共享库 <binary> 需要的确切版本(NEEDED 属性)以及在何处查找它们(RPATH 属性)查看标准 linker 目录(/etc/ld.so.conf/ 中的配置)。

如果您确实希望将库的路径硬编码到可执行文件中,则需要将以下内容传递给 gcc:

-Wl,-rpath=$HOME/Downloads/readline/shlib

不推荐设置自定义LD_LIBRARY_PATH,如果要使用,将其作为参数执行即可。

LD_LIBRARY_PATH=$HOME/Downloads/readline/shlib ./rc