解决 Linux 中的“无法打开共享库文件:没有这样的文件或目录”错误
1. 概述
在本教程中,我们将介绍Linux中“无法打开共享对象文件:没有此类文件或目录”错误的各种原因和修复方法。
2. 什么是共享库?
Linux 中的共享库 为程序提供了各种可重用的功能。 假设我们要编写一个将压缩文件作为输入的程序。为此,我们可以使用现有的库,例如zlib ,而不是自己实现解压功能。
程序在启动时加载共享库。
此外,我们可以使用**ldd 命令列出程序使用的所有共享库:**
$ ldd /usr/bin/clang
/usr/bin/clang:
linux-vdso.so.1 (0x00007ffd34a90000)
libclang-cpp.so.13 => /usr/bin/../lib/libclang-cpp.so.13 (0x00007f24c5a94000)
libLLVM-13.so => /usr/bin/../lib/libLLVM-13.so (0x00007f24c1548000)
libstdc++.so.6 => /usr/bin/../lib/libstdc++.so.6 (0x00007f24c12d6000)
libm.so.6 => /usr/bin/../lib/libm.so.6 (0x00007f24c11f8000)
libgcc_s.so.1 => /usr/bin/../lib/libgcc_s.so.1 (0x00007f24c11dd000)
libc.so.6 => /usr/bin/../lib/libc.so.6 (0x00007f24c0fc4000)
/lib/ld-linux-x86-64.so.2 => /usr/lib/ld-linux-x86-64.so.2 (0x00007f24c95d4000)
libz.so.1 => /usr/bin/../lib/../lib/libz.so.1 (0x00007f24c0fad000)
在这里,我们可以看到clang 编译器需要各种库(例如LLVM )才能运行。
正如我们所见,共享库以*.so*扩展名结尾。
有时,共享库可能不存在或可能位于非标准路径中。结果,我们在程序启动时得到“无法打开共享对象文件:没有这样的文件或目录” 。**
3. 缺少包
有时,我们可能只是缺少提供所需共享库的包。
例如,如果一个程序抱怨缺少libzstd.so,我们可以尝试在系统的包管理器中搜索它。
在基于apt 的系统上,我们可以使用apt search命令:
$ apt search zstd
Sorting... Done
Full Text Search... Done
zstd/stable 1.5.0 aarch64
Zstandard compression.
现在,我们可以使用apt install安装缺少的软件包。但是,我们必须注意,这种方法不是很可靠,并且需要一些猜测才能找到包名。
在上面的示例中,缺少的库的名称是libzstd.so,但没有名为libzstd的包。结果,我们不得不猜测并只搜索zstd。
4. LD_LIBRARY_PATH变量
我们可以在LD_LIBRARY_PATH环境变量中指定要搜索共享库的目录。
LD_LIBRARY_PATH是一个以冒号分隔的目录列表,就像PATH 变量一样。
默认搜索路径通常限于/usr/lib和/usr/local/lib。**
假设我们有一个链接到libfoo.so的程序,位于*/home/blogdemo/libs/libfoo.so*,它位于默认搜索路径之外。然后,我们可以使用此变量附加到搜索路径并解决问题。
首先,让我们使用ldd命令确认程序链接到的确切库:
$ ./program
./program: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
$ ldd ./program
./program:
linux-vdso.so.1 (0x00007ffce871b000)
libfoo.so => not found
libc.so.6 => /usr/lib/libc.so.6 (0x00007fdceadaf000)
/lib/ld-linux-x86-64.so.2 => /usr/lib/ld-linux-x86-64.so.2 (0x00007fdceafd3000)
现在,让我们将目录添加到LD_LIBRARY_PATH并让我们的程序运行:
$ export LD_LIBRARY_PATH=/home/blogdemo/libs
$ ldd ./program
./program:
linux-vdso.so.1 (0x00007ffe28dfd000)
libfoo.so => /home/blogdemo/libs/libfoo.so (0x00007f8f0f7ba000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f8f0f59d000)
/lib/ld-linux-x86-64.so.2 => /usr/lib/ld-linux-x86-64.so.2 (0x00007f8f0f7c6000)
此外,如果我们不知道库在哪里,我们可以使用find 命令在常见路径中找到它,例如*/home或/usr*:
$ find /home -type f -name libfoo.so
/home/blogdemo/libs/libfoo.so
5. 永久配置库路径
我们可以使用*/etc/ld.so.conf*文件来永久设置库搜索路径。在这个文件中,我们指定了一个以换行符分隔的目录列表。
让我们再次修复libfoo.so错误:
$ ./program
./program: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
$ echo "/home/blogdemo/libs" | sudo tee /etc/ld.so.conf
/home/blogdemo/libs
$ sudo ldconfig
$ ldd ./program
./program:
linux-vdso.so.1 (0x00007ffefc3db000)
libfoo.so => /home/blogdemo/libs/libfoo.so (0x00007f021e88d000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f021e674000)
/lib/ld-linux-x86-64.so.2 => /usr/lib/ld-linux-x86-64.so.2 (0x00007f021e89e000)
我们必须运行一次ldconfig命令以使系统知道新路径。
6. ldconfig命令
我们可能最近安装了新的共享库或修改了共享库搜索路径。因此,我们需要运行ldconfig 命令。
它更新链接器的缓存以使其了解新的共享库。
链接器,称为ld.so 加载程序的共享库。
我们可以使用*-p标志调用ldconfig*来检查当前缓存:
$ ldconfig -p
347 libs found in cache `/etc/ld.so.cache'
libzstd.so.1 (libc6,x86-64) => /usr/lib/libzstd.so.1
libzstd.so (libc6,x86-64) => /usr/lib/libzstd.so
libz.so.1 (libc6,x86-64) => /usr/lib/libz.so.1
libz.so (libc6,x86-64) => /usr/lib/libz.so
libx265.so.199 (libc6,x86-64) => /usr/lib/libx265.so.199
libx265.so (libc6,x86-64) => /usr/lib/libx265.so
libx264.so.157 (libc6,x86-64) => /usr/lib/libx264.so.157
libx264.so (libc6,x86-64) => /usr/lib/libx264.so
...
从这个输出中,我们可以确定各种共享库的确切位置。
7. 在编译时设置库路径
如果我们可以访问程序的源代码,我们可以在链接过程中 使用特殊标志对其进行编译, 以便可以找到共享库。
我们可以在运行时使用ld 的*-rpath*标志将库路径传递给动态链接器。
让我们编译一个基本程序并将其链接到我们的库:
$ pwd
/home/blogdemo/libs
$ ls
libfoo.so
$ echo "int main() {}" > program.c # Dummy program
$ cc program.c libfoo.so # Link to our library
$ ./a.out
./a.out: error while loading shared libraries: libfoo.so: cannot open shared object file: No such file or directory
$ ldd ./a.out
./a.out:
linux-vdso.so.1 (0x00007ffcbc1f8000)
libfoo.so => not found
libc.so.6 => /usr/lib/libc.so.6 (0x00007feb0ee04000)
/lib/ld-linux-x86-64.so.2 => /usr/lib/ld-linux-x86-64.so.2 (0x00007feb0f029000)
我们可以看到程序无法加载我们的共享库。
现在,让我们尝试使用 -rpath 标志编译它,将* /home/blogdemo/libs*添加到库搜索路径:
$ gcc program.c libfoo.so -Wl,-rpath=/home/blogdemo/libs
$ ldd ./a.out
./a.out:
linux-vdso.so.1 (0x00007ffd0fbad000)
libfoo.so => /home/blogdemo/libs/libfoo.so (0x00007fba09d99000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fba09b7b000)
/lib/ld-linux-x86-64.so.2 => /usr/lib/ld-linux-x86-64.so.2 (0x00007fba09da5000)
在这里,我们使用gcc 的*-Wl标志将参数传递给ld*。