gcc链接指定路径中的共享库,但不在标准路径中

时间:2015-03-02 09:19:22

标签: c linux gcc linker shared-libraries

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

当我下载GNU readline library version 6.3并在路径 $ HOME / Downloads 中成功编译时。

GNU readline库需要链接 libtinfo ,所以我按sudo apt-get install libtinfo安装了它。

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

$ 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 链接库:

$ 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)

我也尝试过anther命令,但结果相同:

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

那么,为什么 /ll 喜欢 /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

3 个答案:

答案 0 :(得分:3)

您还需要一个名为libreadline.so.6的符号链接,而不仅仅是libreadline.so。原因是soname的{​​{1}}为libreadline.so.6.3

libreadline.so.6是"泛型"嵌入在库本身中的名称。当您链接到具有soname的共享库时,该名称将嵌入您的可执行文件中,稍后由动态链接程序查找。 (对于没有soname的共享库,会使用文件名,但这种情况并不常见。)您可以通过运行来判断库的sonames是什么。

soname

objdump -p <library> | grep SONAME s的目的是使您的可执行文件链接到应该兼容的最通用的库名称(通常这是只有主要版本的库名称 - 在这种情况下为6 - 加上),而不仅仅是您碰巧链接的特定(例如,小错误修复版本)版本。

soname的输出也告诉您它专门针对ldd

答案 1 :(得分:1)

如果您真的想要在可执行文件中硬编码库的路径,则需要将以下内容传递给gcc:

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

不建议设置自定义LD_LIBRARY_PATH,如果要使用它,请将其用作执行参数。

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

答案 2 :(得分:0)

这是解决问题的替代方法:

  1. 链接到.so的完整路径。 E.g。

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

    正如@Ulfalizer建议的那样,您可能需要另一个只包含主要数字的符号链接。

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

  3. 使用-L<path>时也使用-Wl,-rpath,<path>,以便运行时链接程序ld.so.2在与ld相同的路径中找到共享库,例如:

    $ gcc -o rl rl.c -I$HOME/Downloads -L$HOME/Downloads/readline/shlib -Wl,-rpath,$HOME/Downloads/readline/shlib -lreadline -ltinfo
    
  4. 调试链接器问题时,使用readelf -d <binary>命令查看共享库<binary>需要哪些确切版本(NEEDED属性)以及在查找标准链接器目录之前查找它们的位置(RPATH属性) (在/etc/ld.so.conf /)中配置。