为什么我需要在安装我的二进制文件后设置 LD_LIBRARY_PATH?

Why do I need to set LD_LIBRARY_PATH after installing my binary?

我的应用程序正在链接到 /usr/local/lib 中的自编译 Qt。

当我在构建目录中启动我的应用程序时,这工作正常。但是,在我将我的应用程序安装到 /usr/local/bin/ 之后,它会尝试加载不兼容的系统 Qt 库,该库没有所需的符号并失败。

为什么?我的二进制文件的实际位置如何影响正在解析的 Qt?

如果我使用 LD_LIBRARY_PATH=/usr/local/lib 启动我的应用程序,它会按预期运行。

Why do I need to set LD_LIBRARY_PATH after installing my binary?

简单的回答是,这是系统架构师和工具链的失败。在 Linux 他们是维护 Binutils 和 glibc 的人。总的来说,维护者认为编译和 link 针对一个版本的库是可以的,然后 运行time link 针对错误版本的库或丢失库。他们确定这是第一个用例 (q.v.)。事情不是开箱即用的,你必须做一些特别的事情才能进入一个好的状态。

考虑一下,我有一些 Build Scripts 可以构建和安装大约 70 个常见的 Linux 实用程序和库,例如 cURL、Git、SSH 和 Wget。这些脚本构建程序及其所有依赖项。有时我会尝试使用它们进行安全测试和评估,例如 Asan 和 UBsan。这个想法是 运行 /usr/local 中的检测程序和库,并检测未定义的行为、内存错误等。然后,将错误报告给项目。

尝试 运行 在 Linux 系统上检测构建是不可能的。例如,一旦 Bzip、iConv、Unicode、IDN、PRCE 和其他几个关键库是使用工具构建的,系统就不再起作用。 /usr/bin 中的程序,如 /usr/bin/bash,将加载 /usr/local/lib 中的检测库。程序和库有很多错误,程序不断被杀死。您不能再 运行 脚本,因为 /usr/bin 中的程序使用了错误的库(并且像 bash 这样的程序有很多错误)。

当然也有像你这样的问题,程序和库找不到自己的库。由于维护者的决定,网络上到处都是大屠杀。


要解决您正在构建的程序的问题,请将以下内容添加到您的 LDFLAGS

-Wl,-R,/usr/local/lib -Wl,--enable-new-dtags

-R,/usr/local/lib 告诉 运行 时间 link 人在 /usr/local/lib 中查找其库。 --enable-new-dtags 告诉 linker 使用 RUNPATH 而不是 RPATH.

RUNPATH 可以用 LD_LIBRARY_PATH 覆盖,而 RPATH 则不能。省略 -Wl,--enable-new-dtags 通常不是一个好主意。另见 Use RPATH but not RUNPATH?.

您也可以使用相对运行时间路径:

-Wl,-R,'$$ORIGIN/../lib' -Wl,--enable-new-dtags

-R,'$$ORIGIN/../lib' 告诉 运行 时间 link 人在 ../lib/ 中查找其库。假设您的二进制文件位于 .../bin/,因此 ../lib/ 位于 lib/ 目录。

基于 ORIGIN 的 linker 路径适用于文件系统布局,例如:

My_App
  |
  +-- bin
  |    |
  |    +- my_app.exe
  |
  +-- lib
  |    |
  |    +- my_lib.so
  |
  +-- share

您可以在文件系统中移动 My_App 文件夹,my_app.exe 将始终能够找到它的库 my_lib.so。如果 My_App 是根目录 /,则它是发行版使用的标准 Linux 文件系统(即 --prefix=/)。如果 My_App/usr/local,则它是用户使用的标准 Linux 文件系统(即 --prefix=/usr/local)。

如果你configuremakemake test,那么你可以使用LD_LIBRARY_PATH来设置测试库的临时路径(如.../My_App/lib).事实上,一个写得好的 make test 应该在测试期间为你做到这一点。


您不必添加 -Wl,-R,/usr/local/lib -Wl,--enable-new-dtags,因为程序是针对 /usr/local/lib 中的库编译和 linked(大概使用 -L<path>-l<lib>).你必须这样做的原因是因为维护者一遍又一遍地犯同样的错误。这是一个彻头彻尾的工程失败。

Linux 架构师在大约 25 年前决定开箱即用时就被警告过这些路径问题。有两个阵营 - 一个希望开箱即用,另一个希望用户做一些特别的事情来让事情正常工作。后来赢得了辩论。他们选择了 "let's link against the wrong library" 和 "let's lose the library" 模式。我希望我能在讨论它的地方找到 Usenet 帖子,这样你就可以自己阅读了。