链接时LD_LIBRARY_PATH和-L有什么区别?

时间:2009-12-15 03:29:34

标签: linux gcc linker shared-libraries

我在链接时遇到LD_LIBRARY_PATH问题(此问题与运行时间无关)。

当我运行make时,链接行看起来像这样(这是使用g ++版本4.1.x的Linux系统):

g++ a.o b.o c.o -o myapp \
 -L/long/path/to/libs/ \
 -L/another/long/path/ \
 -labc -ldef -lghi

-l选项引用存在于-L选项指定的目录中的共享库(例如,libabc.so)。这些目录也出现在LD_LIBRARY_PATH中。使用该配置,链接成功,我可以运行该应用程序。

如果我从LD_LIBRARY_PATH删除目录,那么我会得到一个错误行,例如:

/usr/bin/ld: cannot find -labc

另一方面,如果我从-L选项列表中删除目录,那么我会收到很多警告,例如:

/usr/bin/ld: warning: libabc.so, needed by /long/path/to/libs/libxyz.so,
    not found (try using -rpath or -rpath-link)

然后还有更多错误,例如:

/long/path/to/libs/libdef.so: undefined reference to `Foo::Bar<Baz>::junk(Fred*)'

有人可以解释LD_LIBRARY_PATH-L之间的区别吗?我想深入了解这些内容,所以非常感谢参考!

此外,我还需要添加哪些内容以避免使用LD_LIBRARY_PATH

编辑:-L中缺少目录时,编译器建议“尝试使用-rpath或-rpath-link”。我不认为我以前见过makefile中的那些选项。你呢?不确定这是否有助于LD_LIBRARY_PATH问题。

5 个答案:

答案 0 :(得分:32)

这个问题有两个答案,部分答案在于编译时链接(即gcc -lfoo -L/usr/lib ...反过来调用ld)和运行时链接器查找。

编译程序时,编译器检查语法,然后链接器确保存在执行所需的符号(即变量/方法/等)等。如前所述,LD_LIBRARY_PATH具有改变gcc / ld行为方式的副作用,以及通过修改搜索路径来改变运行时链接程序的行为方式。

运行程序时,运行时链接程序实际上会提取共享库(如果可能,在磁盘上或内存中),并加载共享符号/代码/等。再次,LD_LIBRARY_PATH会影响此搜索隐含的路径(有时候并不是好事,如上所述。)

在大多数Linux系统上不使用LD_LIBRARY_PATH的正确解决方法是将包含共享库的路径添加到/etc/ld.so.conf(或在某些发行版中,在/etc/ld.so.conf.d/中创建文件使用其中的路径)并以root身份运行ldconfig/sbin/ldconfig)以更新运行时链接程序绑定缓存。

关于Debian的例子:

jewart@dorfl:~$ cat /etc/ld.so.conf.d/usrlocal.conf 
/usr/local/lib

然后,当程序执行时,运行时链接程序将在这些目录中查找已链接二进制文件的库。

如果您想知道运行时链接器知道哪些库,可以使用:

jewart@dorfl:~$ ldconfig -v 

/usr/lib:
libbfd-2.18.0.20080103.so -> libbfd-2.18.0.20080103.so
libkdb5.so.4 -> libkdb5.so.4.0
libXext.so.6 -> libXext.so.6.4.0

而且,如果您想知道二进制文件链接到哪些库,您可以使用ldd之类的函数,这将告诉您运行时链接程序将选择哪个库:

jewart@dorfl:~$ ldd /bin/ls
linux-vdso.so.1 =>  (0x00007fffda1ff000)
librt.so.1 => /lib/librt.so.1 (0x00007f5d2149b000)
libselinux.so.1 => /lib/libselinux.so.1 (0x00007f5d2127f000)
libacl.so.1 => /lib/libacl.so.1 (0x00007f5d21077000)
libc.so.6 => /lib/libc.so.6 (0x00007f5d20d23000)

答案 1 :(得分:20)

LD_LIBRARY_PATH的设置具有最高优先级,因此在设置时,LD_LIBRARY_PATH提到的目录集将首先在标准集之前搜索 目录。因此,在您的情况下,LD_LIBRARY_PATH的设置正在影响查找 使用-l选项提到的库。没有LD_LIBRARY_PATH一些依赖关系 可能已从标准目录集解析。

虽然设置LD_LIBRARY_PATH有助于调试并尝试更新版本的
库在一般开发环境设置和部署中的使用被认为是错误的。

有关共享库的更多详细信息,请参阅Linux文档中的this HOWTO

答案 2 :(得分:8)

LD_LIBRARY_PATH用于在运行应用程序时查找共享库。这是一个副作用,它会影响你的链接,你不应该依赖它。

  

作为一种常常不必要的副作用,   还将搜索LD_LIBRARY_PATH   在目录后的链接(ld)阶段   用-L指定(如果没有-L标志也是如此)   给出了。)

Why LD_LIBRARY_PATH is bad

答案 3 :(得分:3)

如果我猜测,我会说链接器正在回归使用LD_LIBRARY_PATH来解析直接链接的库(例如libabc.solibdef.so和{{ 1}})动态链接。查看libghi.so的手册页,看起来与使用ld构建的.so链接会影响动态绑定符号的查找工作方式。

答案 4 :(得分:1)

检查man的g ++,我发现-lxxxxx选项在提供的路径libxxxxx.a中寻找-L,所以在链接时,只有.a个文件加载。在运行时,如果缺少一个库,那么只有库作为共享对象,所以.so将被加载,然后它将在LD_LIBRARY_PATH中查找。在我正在处理的可执行文件上,我看到在某些库目录中,有版本libxxxx.alibxxxx.so所以我认为这意味着库可以在链接时链接或链接在将运行时作为共享对象。

如果库仅作为共享对象存在,则意味着库目录路径需要在运行时找到LD_LIBRARY_PATH。 如果一个库只作为一个存档而存在,那么它就意味着它需要在可执行文件的构建时进行链接,然后-L目录路径和-lxxxxx需要在编译时以g ++的形式提供。

这是我的理解......至少它符合你的观察