我的应用程序链接到位于/usr/local/lib
中的自编译Qt。
当我在构建目录中启动我的应用程序时,此方法工作正常。但是,在将我的应用程序安装到/usr/local/bin/
之后,它尝试加载没有必需符号且不成功的不兼容系统Qt lib。
为什么?我的二进制文件的实际位置如何影响正在解决的Qt?
如果我使用LD_LIBRARY_PATH=/usr/local/lib
启动我的应用,则它会按预期工作。
答案 0 :(得分:2)
为什么安装二进制文件后需要设置LD_LIBRARY_PATH?
简单的答案是,这是系统架构师和工具链的失败。在Linux上,他们是维护Binutils和glibc的人。总体而言,维护人员认为可以针对一个版本的库进行编译和链接,然后针对错误版本的库进行运行或链接,或者丢失该库。他们确定这是第一个用例( 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
告诉运行时链接程序在/usr/local/lib
中查找其库。 --enable-new-dtags
告诉链接器使用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'
告诉运行时链接程序在../lib/
中查找其库。假定您的二进制文件位于.../bin/
中,因此../lib/
会向上移动到lib/
目录。
当您具有如下文件系统布局时,基于ORIGIN的链接器路径是很好的选择:
My_App
|
+-- bin
| |
| +- my_app.exe
|
+-- lib
| |
| +- my_lib.so
|
+-- share
您可以在文件系统中移动My_App
文件夹,my_app.exe
将始终能够找到其库my_lib.so
。并且,如果My_App
是根目录/
,则它是发行版(即--prefix=/
)使用的标准Linux文件系统。并且,如果My_App
是/usr/local
,则它是用户(即--prefix=/usr/local
)使用的标准Linux文件系统。
如果您使用configure
,make
和make test
,则可以使用LD_LIBRARY_PATH
设置用于测试的库的临时路径(例如.../My_App/lib
) 。实际上,写得好的make test
应该可以在测试期间为您做到这一点。
您无需添加-Wl,-R,/usr/local/lib -Wl,--enable-new-dtags
,因为程序已编译并与/usr/local/lib
中的库链接(大概使用-L<path>
和-l<lib>
)。您必须这样做的原因是,维护人员不断重复犯同样的错误。这是完全的工程失败。
大约25年前,Linux架构师在决定要做什么时就警告这些路径问题。有两个阵营-一个希望开箱即用的东西,另一个想要用户做一些特殊的事情来使事情正常工作。后来赢得了辩论。他们选择了“让我们链接到错误的库”和“让我们丢失库”模式。希望我可以在讨论它的Usenet帖子中找到它,以便您自己阅读。