【问题标题】:Why do I have to define LD_LIBRARY_PATH with an export every time I run my application?为什么每次运行应用程序时都必须使用导出定义 LD_LIBRARY_PATH?
【发布时间】:2010-10-16 06:46:51
【问题描述】:

我有一些代码使用了一些共享库(gcc 上的 c 代码)。编译时,我必须使用 -I 和 -L 显式定义包含和库目录,因为它们不在标准位置。当我尝试运行代码时,出现以下错误:

./sync_test 
./sync_test: error while loading shared libraries: libsync.so: cannot open shared object file: No such file or directory

但是,执行以下操作,一切正常:

export LD_LIBRARY_PATH="/path/to/library/"
./sync_test

现在,奇怪的是,这只能工作一次。如果我再次尝试运行sync_test,我会得到同样的错误,除非我先运行导出命令。我尝试将以下内容添加到我的 .bashrc 中,但没有任何区别:

LD_LIBRARY_PATH="/path/to/library/"

【问题讨论】:

  • 我认为所有这些建议都很糟糕——显然是 Linux 的一个错误。为什么编译时 L 路径没有传递给运行时?
  • 您可以使用-rpath 设置路径,但这通常是不可取的,因为它会将该路径强加于其他系统 - 请参阅stackoverflow.com/a/695539/168175 的第二条评论

标签: c linux gcc shared-libraries ld


【解决方案1】:

您应该避免在您的.bashrc 中设置LD_LIBRARY_PATH。请参阅"Why LD_LIBRARY_PATH is bad" 了解更多信息。

在链接时使用链接器选项-rpath,以便动态链接器知道在运行时在哪里可以找到libsync.so

gcc ... -Wl,-rpath /path/to/library -L/path/to/library -lsync -o sync_test

编辑:

另一种方法是使用这样的包装器

#!/bin/bash

LD_LIBRARY_PATH=/path/to/library sync_test "$@"

如果sync_test 启动任何其他程序,它们最终可能会使用/path/to/library 中的库,这可能是也可能不是有意的。

【讨论】:

  • 如果您将应用程序移动到其他人的机器并且他们不想将库放在与您在链接时期望的相同的 /path/to 中,那真的没有帮助。虽然 -rpath 对于系统管理员和发行版提供商来说肯定很有用,但我认为个人设置它是冒昧的。
  • 虽然,你的第一句话“避免在你的 .bashrc 中设置 LD_LIBRARY_PATH”我同意 100%。我使用的中间解决方案是一个 bash 脚本 $HOME/bin/myprogram,它设置本地 LD_LIBRARY_PATH,然后运行 ​​/path/to/real/myprogram。
  • 你是对的。不能假设有人想要他们的库。如果 bin/ 和 lib/ 之间存在固定关系,则 -rpath $ORIGIN/../lib 之类的内容可能更合适。还有一个程序可以更改 ELF 可执行文件中的 rpath,称为 chrpath。
  • 我同意使用包装外壳脚本。我会更新我的答案。
  • 感谢您的提示。文章中提到的所有事情对我来说都不是真正的问题(这段代码只会由我在一台机器上运行),但如果我遇到类似的问题,我一定会记住它们。
【解决方案2】:

使用

export LD_LIBRARY_PATH="/path/to/library/"

在你的 .bashrc 中,否则它只能用于 bash 而不是你启动的任何程序。

在链接时尝试-R/path/to/library/ 标志,它会使程序在该目录中查找,您无需设置任何环境变量。

编辑:看起来-R 仅适用于 Solaris,而您使用的是 Linux。

另一种方法是将路径添加到/etc/ld.so.conf 并运行ldconfig。请注意,这是一个适用于所有动态链接的二进制文件的全局更改。

【讨论】:

  • 使用-Wl,-rpath(如果传递给cc)或-rpath(如果传递给ld)比-R更便携。
  • -rpath 可能有问题,请参阅wiki.debian.org/RpathIssue 进行讨论
  • 为了兼容性,GNU ld 也支持 -R,尽管正如 @awoodland 的评论中提到的那样,这是不受欢迎的。 (我想说的是“十大商业软件错误”)
【解决方案3】:

你可以把这些都放在一行上:

LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/path/to/library" ./sync_test

应该让事情变得更容易一些,即使它不会改变任何基本的东西

【讨论】:

  • 这个语法太棒了...特别是如果您的某些程序行为基于瞬态环境变量,例如 TMP 或 TMPDIR
【解决方案4】:

您是否在 .bashrc 中“导出”了?

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"/path/to/library"

【讨论】:

    【解决方案5】:

    您可以使用rpath 将其烘焙到二进制文件本身,而不是在运行时使用 LD_LIBRARY_PATH 覆盖库搜索路径。如果您与 GCC 链接添加 -Wl,-rpath,<libdir> 应该可以解决问题,如果您与 ld 链接它只是 -rpath <libdir>

    【讨论】:

      【解决方案6】:

      如果它是您在系统上安装的东西,您还可以做的是将包含共享库的目录添加到您的 /etc/ld.so.conf 文件中,或者创建一个/etc/ld.so.conf.d/

      中的新文件

      (我已经检查了 RHEL5 和 Ubuntu 发行版,所以我认为它对于 linux 来说是通用的)

      ldconfig 程序将确保它们被包含在系统范围内。

      有关详细信息,请参阅以下链接: www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/dlls.html

      【讨论】:

        【解决方案7】:

        您可以在代码中添加具有新定义的呼叫系统:

        sprintf(newdef,"export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:%s:%s",ld1,ld2);
        system(newdef);
        

        但是,我不知道这是正确的解决方案,但它有效。

        问候

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-01-29
          • 2013-05-28
          • 1970-01-01
          • 1970-01-01
          • 2017-12-22
          • 1970-01-01
          相关资源
          最近更新 更多