C++ linux 可执行文件不断尝试使用不存在的库

C++ linux executable keeps trying to use library that does not exist

我正尝试在 Linux 上使用 GLFW 编写一个简单的应用程序。现在主文件(唯一的文件)基本上只是几行代码来确保动态库正确链接。这是:

#include <GLFW/glfw3.h>
#include <iostream>

int main()
{
    glfwInit();
    std::cout << "It works this far!" << std::endl;
    glfwTerminate();
}

包含文件存储在标有 "include" 的目录中,库文件存储在标有 "lib" 的目录中。截至目前,我正在使用以下行编译程序:

g++ -Wl,-Rlib -Iinclude -Llib test.cpp -o test -lglfw.3.2

它编译和链接都很好,但是当我尝试执行它时,出现以下错误:

./test: error while loading shared libraries: libglfw.so.3: cannot open shared object file: No such file or directory

现在,在您急于将这个问题否决并标记为重复之前,至少请允许我解释一下为什么我认为我的问题足够不同以至于不会重复。 我已经尝试了其他问题提出的解决方案,但没有成功。如您所见,我尝试在与 -Wl,-Rlib 标记链接期间设置库的路径。我还尝试将 LD_LIBRARY_PATH 设置为指向我的库的位置('lib' 文件夹),但它仍然抛出相同的错误。 (路径是相对路径还是绝对路径并不重要。)

因此,我接下来尝试的是 运行 可执行文件上的 ldd 命令。我得到了一些其他工作正常的依赖项,但重要的是,我得到了这个:

libglfw.so.3 => not found

不知为何,硬要找libglfw.so.3。它不会有任何其他方式。 将库从 libglfw.3.2.so 重命名为 libglfw.so.3 后,程序执行得很好并打印 It works this far! 就好像根本没有问题一样。

为什么会这样?

For some reason, it insists on looking for libglfw.so.3. It will not have it any other way.

这是共享库的 Linux 约定,在其他地方 here 进行了描述。因为 Linux libfoo.so.x.y.z 被认为具有与 libfoo.so.x 相同的 ABI。通常在安装共享库时(例如通过 rpm、dpkg 等)会调用 ldconfig,这样刚安装的库就会有一个遵循引用该库的约定安装的符号链接。出于性能原因,这些库(如果安装到 "trusted location")也被添加到链接器缓存中。

It compiles and links just fine, but when I try to execute it, I get the following error:

./test: error while loading shared libraries: libglfw.so.3: cannot open shared object file: No such file or directory

libglfw.so.3 不在 ld-linux.so 的路径上。

As you can see, I tried setting the path to the library during linking with the -Wl,-Rlib

仍然找不到它 -- libglfw.so.3 不在 ld-linux.so 的路径上。您可以通过执行以下操作来添加它:

ldconfig -n /path/to/lib

这应该为您的库输出必要的 libglfw.so.3 符号链接。 IIRC 设置 rpath 可能需要完整路径。

I also tried setting LD_LIBRARY_PATH to point to the location of my libraries

同样,libglfw.so.3 不在 ld-linux.so 的路径上。

For some reason, it insists on looking for libglfw.so.3. ... Upon renaming the library from libglfw.3.2.so to libglfw.so.3 ...

ELF 可执行文件包含所用动态库的确切名称。

如果可执行文件包含库名称“libglfw.so.3”,则文件必须完全这样命名。

文件命名方案是有意以不将 "full" 版本编码到文件名中的方式完成的:这样,更高版本 ("libglfw.so.3.15") 将与可执行文件一起使用.

通常应该有一个符号 link 到安装的最新版本的库:

libglfw.so.3 -> libglfw.so.3.2

您的计算机上似乎缺少此符号 link。我会说这是一个安装问题!

编辑

问题可能是:为什么可执行文件中存储的文件名不是libglfw.3.2.so而是libglfw.so.3

答案与安装新版本库时的向后兼容性有关:

通常您会使用开关 -lglfw 并查找名为 libglfw.so 的符号 link。

如果您将文件名 libglfw.so 存储在可执行文件中,并且如果安装了此库 (libglfw.so.4) 的新的不兼容版本,您将没有机会获得该程序 运行 通过安装两个版本的库。

要通过安装两个版本的库来实现向后兼容性,库的 "real" 符号 link 名称 (libglfw.so.3) 必须存储在可执行文件中。

因此,库的 "expected" 文件名存储在库本身中:在文件 libglfw.so.3.2 中,您会发现一些信息,文件希望自己存储为 libglfw.so.3.

linker 将使用有关文件名的此信息,因为它假定 linker 开关 (-lglfw) 中给出的库名称小于 "precise" 而不是存储在库本身中的名称。