【问题标题】:Why LD_LIBRARY_PATH is BAD and the correct way to load dynamic libraries为什么 LD_LIBRARY_PATH 不好以及加载动态库的正确方法
【发布时间】:2024-01-29 09:25:01
【问题描述】:

所以,我有一个与 OpenBlas 一起运行的程序,我想编译它。链接过程如下所示:

gcc -o prog prog.o -O3 -I/opt/OpenBLAS/include -L/opt/OpenBLAS/lib -lopenblas

到目前为止一切顺利。如果我删除 -L 选项,我会在链接过程中收到错误

/usr/bin/ld: cannot find -lopenblas

使用-Leverything 链接没有错误。但是,当我尝试运行它时,出现以下错误:

./prog: error while loading shared libraries: libopenblas.so.0: cannot open shared object file: No such file or directory

如果我将环境变量LD_LIBRARY_PATH 设置为/opt/OpenBlas/lib,我可以运行程序,但是像http://xahlee.info/UnixResource_dir/_/ldpath.html 这样的许多来源认为这是一种不好的做法,我几乎可以理解所有推理。文章中提到的另一种方法(修改 ld 配置)也被认为是一种不好的做法。最后,您可以在/usr/lib 中向库添加符号链接。最后两种方法的一个大问题是您需要 sudo 访问权限。

所以我的问题是如何在不使用LD_LIBRARY_PATH 和 sudo 访问的情况下编译和运行链接到不在默认路径 (/usr/lib) 中的共享库的程序。在文章中,他们说您可以在二进制文件中“写入”以查找共享库,但我不知道该怎么做(-L 标志似乎没有这样做)。如果有人能解释这个问题,我将不胜感激,因为我一直在到处寻找并且我很困惑(一些参考资料似乎表明标志 '-L' 应该这样做,但我不适合我)。提前谢谢你。

【问题讨论】:

  • 可以使用-rpath设置运行库搜索路径

标签: c++ c compiler-errors shared-libraries


【解决方案1】:

将路径添加到运行时库搜索路径。

gcc -Wl,-rpath=/opt/OpenBlas/lib ...

-L 选项在链接时的作用,-rpath 选项在运行时的作用。

【讨论】:

  • 这可能是 OP 正在寻找的答案,尽管它也很糟糕,因为它将路径构建到可执行文件中,需要重新编译可执行文件以重新定位库。因此,您应该基本上了解所有解决方案,为什么它们都不好,然后选择对您的用例最不坏的解决方案。 ;)
  • @DavidSchwartz:您可以在不重新编译的情况下重新定位库,您只需将其重新定位到运行时搜索路径中的其他位置...如果您不使用@,这与您的选择相同987654325@。如果您真的想将库移动到其他地方,您可以随时使用LD_LIBRARY_PATH。抱歉,除了将二进制文件复制到另一个系统时-rpath 可能有点嘈杂之外,我没有看到缺点。
  • @DavidSchwartz:您还可以使用chrpath 工具在不重新编译的情况下修改rpath。除非新的 rpath 更短,否则您无法在 OS X 上执行此操作,但遗憾的是,没有什么是完美的。
  • 谢谢!这确实是我一直在寻找的答案。但是,我在文档 gcc.gnu.org/onlinedocs/gcc/Option-Summary.html#Option-Summary 中找不到 -rpath 选项。我还想知道 -Wl 选项的用途是什么,是否有必要。
  • “-Wl”是将rpath选项传递给链接器,“ld”是在创建可执行文件时传递的。
【解决方案2】:

在 linux 上,也可以在 rpath 中使用 $ORIGIN 来表示应用程序的目录路径,并从那里构建相对 rpath。然后,您可以将库移动到二进制文件的已知相对路径。

gcc -o prog prog.o -O3 -I/opt/OpenBLAS/include -Wl,-rpath=\$ORIGIN/lib -L/opt/OpenBLAS/lib -lopenblas

您也可以使用库的完整路径,它将链接到:

gcc -o prog prog.o -O3 -I/opt/OpenBLAS/include /opt/OpenBLAS/lib/libopenblas.so

如果您在可执行文件上运行“ldd”,您应该会看到已编码的完整路径。

【讨论】:

  • 您需要引用$ORIGIN,否则shell 会将其展开(可能为空字符串)。 '-Wl,-rpath=$ORIGIN/lib' 会起作用。
最近更新 更多