如何指定库路径的首选项?


91

我正在使用g++和编译c ++程序ld。我有一个.so我想在链接期间使用的库。但是,中存在一个同名的库/usr/local/lib,并且ld正在选择该库而不是我直接指定的库。我怎样才能解决这个问题?

对于以下示例,我的库文件为/my/dir/libfoo.so.0。我尝试过的事情不起作用:

  • 我的g ++命令是 g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • 添加/my/dir到我的$PATHen`变量的开头或结尾
  • /my/dir/libfoo.so.0作为g ++的参数添加

1
还有哪些其他libfoo.*文件,以及在什么位置-不.so包含.0.a等?
亚历克斯·马特利

Answers:


92

将路径添加到新库的位置LD_LIBRARY_PATH(在Mac上名称稍有不同...)

您的解决方案应该使用这些-L/my/dir -lfoo选项,在运行时使用LD_LIBRARY_PATH指向您的库的位置。

谨慎使用LD_LIBRARY_PATH-简而言之(来自链接):

..implications ..:
安全性:还记得在LD_LIBRARY_PATH中指定的目录在标准位置之前(!)被搜索吗?这样,一个讨厌的人可能会让您的应用程序加载包含恶意代码的共享库的版本!这就是setuid / setgid可执行文件忽略该变量的原因之一!
性能:链接加载器必须搜索所有指定的目录,直到找到共享库所在的目录–对于应用程序链接到的所有共享库!这意味着很多系统对open()的调用都会失败,并显示“ ENOENT(没有这样的文件或目录)”!如果路径包含许多目录,则失败的调用数将线性增加,您可以从应用程序的启动时间得知这一点。如果某些(或全部)目录位于NFS环境中,则应用程序的启动时间实际上可能会很长-并且会减慢整个系统的速度!
前后矛盾:这是最常见的问题。LD_LIBRARY_PATH强制应用程序加载未链接的共享库,这很可能与原始版本不兼容。这可能很明显,即应用程序崩溃,或者如果拾取的库执行的操作与原始版本不一样,则可能导致错误的结果。特别是后者有时很难调试。

要么

通过gcc使用rpath选项链接到链接器-将使用运行时库搜索路径代替查找标准目录(gcc选项):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

这对于临时解决方案很有用。链接器在查找标准目录之前,首先在LD_LIBRARY_PATH中搜索库。

如果您不想永久更新LD_LIBRARY_PATH,可以在命令行中即时执行:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

您可以检查链接器知道使用哪些库(示例):

/sbin/ldconfig -p | grep libpthread
        libpthread.so.0 (libc6, OS ABI: Linux 2.6.4) => /lib/libpthread.so.0

您可以检查您的应用程序正在使用哪个库:

ldd foo
        linux-gate.so.1 =>  (0xffffe000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb7f9e000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0xb7e6e000)
        librt.so.1 => /lib/librt.so.1 (0xb7e65000)
        libm.so.6 => /lib/libm.so.6 (0xb7d5b000)
        libc.so.6 => /lib/libc.so.6 (0xb7c2e000)
        /lib/ld-linux.so.2 (0xb7fc7000)
        libdl.so.2 => /lib/libdl.so.2 (0xb7c2a000)
        libz.so.1 => /lib/libz.so.1 (0xb7c18000)

21
LD_LIBRARY_PATH在运行时,要设置的编译时进行搜索LIBRARY_PATH。参见gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
Bjoern Dahlgren

1
如果您的库与系统库完全不同,即是经常使用的库,请使用rpath解决方案。LD_LIBRARY_PATH是用于测试的黑客工具,不应被要求使可执行文件正常工作。
user2746401 2015年

1
Mac版的DYLD_LIBRARY_PATH
cbinder

这是一个基于此答案的完整示例命令(针对C):gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue

25

这是一个古老的问题,但似乎没有人提到过。

您很幸运,这件事根本没有联系。

你需要改变

g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp

对此:

g++ -g -Wall -o my_binary -L/my/dir bar.cpp -lfoo

链接器会跟踪需要解析的符号。如果它先读取该库,则它不需要任何符号,因此它将忽略其中的符号。在需要链接的内容之后指定库,以便链接程序在其中可以找到符号。

也, -lfoo使其专门搜索名为libfoo.alibfoo.so需要的文件。不libfoo.so.0。因此ln,名称或将库重命名为适当的库。

引用gcc手册页:

-l library
   ...
   It makes a difference where in the command you 
   write this option; the linker searches and processes 
   libraries and object files in the order they are 
   specified.  Thus, foo.o -lz bar.o searches library z 
   after file foo.o but before bar.o.  If bar.o refers 
   to functions in z, those functions may not be loaded.

将文件直接添加到g++的命令行应该可以正常工作,除非您当然将其放在之前,否则bar.cpp链接器会因为缺少所需的符号而将其忽略,因为还不需要任何符号。



11

或者,您可以使用环境变量LIBRARY_PATHCPLUS_INCLUDE_PATH,分别指示在何处查找库和在何处查找标头(CPATH也可以完成工作),而无需指定-L和-I选项。

编辑: CPATH包括与报头-ICPLUS_INCLUDE_PATH-isystem


您可以添加用法示例吗?
Hanna Khalil

export LIBRARY_PATH = /path/to/lib在您正在编译的同一控制台会话中
Alexandre Hamez

0

如果使用Windows中的DLL并希望在linux / QT中跳过.so版本号,则添加CONFIG += plugin将删除版本号。如Klatchko先生所述,使用.so的绝对路径,将其提供给链接器工作正常。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.