如何指定库路径的偏好?

新手上路,请多包涵

我正在使用 g++ld 编译一个 c++ 程序。我有一个 .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 添加到我的 $PATH en` 变量的开头或结尾
  • 添加 /my/dir/libfoo.so.0 作为参数到 g++

原文由 Heinrich Schmetterling 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 326
2 个回答

将新库所在的路径添加到 LD_LIBRARY_PATH (它在 Mac 上的名称略有不同……)

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

小心使用 LD_LIBRARY_PATH - 简而言之(来自链接):

..影响..:

安全性:还记得 LD_LIBRARY_PATH 中指定的目录在(!)标准位置之前被搜索过吗?这样,讨厌的人可以让您的应用程序加载包含恶意代码的共享库版本!这就是为什么 setuid/setgid 可执行文件会忽略该变量的原因之一!

性能:链接加载器必须搜索所有指定的目录,直到找到共享库所在的目录——对于应用程序链接的所有共享库!这意味着对 open() 的大量系统调用将失败并显示“ENOENT (No such file or directory)”!如果路径中包含很多目录,调用失败的次数会线性增加,从应用程序的启动时间就可以看出。如果部分(或全部)目录位于 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)

原文由 stefanB 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

你很幸运,这件事完全是联系在一起的。

你需要改变

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 之前,导致链接器因为缺少任何需要的符号而忽略它,因为还不需要符号。

原文由 Michael Speer 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题