Ict-创新/LPI/102.3
候选人应该能够确定可执行程序依赖的共享库,并在必要时安装它们。
关键知识领域
- 识别共享库
- 识别系统库的典型位置。
- 加载共享库。
库是一组函数,程序可以使用这些函数来实现它们的功能。在构建(链接)程序时,这些库可以静态或动态链接到可执行文件。静态链接意味着最终程序将在其文件中包含库函数。(lib.a)动态链接意味着当程序执行时,所需的库将加载到 RAM 中(lib.so)。
在编写应用程序时,开发人员会使用现有的软件库来提供应用程序所需的 functionality。当最终应用程序被编译时,有两种选择可用。
- 使用所有必需的库编译到应用程序中构建应用程序。这被称为将库静态链接到应用程序。这样做的好处是应用程序安装后不会出现依赖性问题,但缺点是二进制文件的大小会增加,因为库在每个静态链接库的应用程序中都重复。最负面的影响是,内核无法通过仅加载一次重复代码来优化内存。相反,每个应用程序都加载了相同的代码。
- 在运行时动态链接所需的依赖项。动态链接的可执行文件比静态链接程序小得多,因为它们不包含它们所依赖的库代码。使用动态链接允许运行使用相同库的程序来共享该库的一个副本,而不是占用内存来存储重复的副本。由于库代码是独立的,因此 Linux 发行版的包管理系统可以独立于应用程序更新库代码。由于这些原因,如今大多数程序都使用动态链接。
为了在运行时查找应用程序所需的库,Linux 需要知道在哪里查找它们。默认情况下,Linux 在以下受信任位置查找库文件
- /lib: - 主要由 /bin 程序使用。
- /usr/lib - 主要由 /usr/bin 程序使用。
库文件的其他位置可以在 /etc/ld.so.conf 文件中指定。ld.so.conf 文件可以包含 /etc/ld.so.conf.d 目录下的所有文件,具体取决于您的发行版。列表 5 显示了 64 位 Fedora 12 系统上的 /etc/ld.so.conf 的内容。
$ cat /etc/ld.so.conf include ld.so.conf.d/*.conf $ ls /etc/ld.so.conf.d/*.conf /etc/ld.so.conf.d/kernel-2.6.31.12-174.2.19.fc12.x86_64.conf /etc/ld.so.conf.d/kernel-2.6.31.12-174.2.22.fc12.x86_64.conf /etc/ld.so.conf.d/kernel-2.6.31.12-174.2.3.fc12.x86_64.conf /etc/ld.so.conf.d/mysql-x86_64.conf /etc/ld.so.conf.d/qt-x86_64.conf /etc/ld.so.conf.d/tix-x86_64.conf /etc/ld.so.conf.d/xulrunner-64.conf |
为了优化库位置和加载,ldconfig 命令会解析 ld.so.conf 文件中的目录和受信任目录,以在 /etc/ld.so.cache 中创建一个快速缓存。
当应用程序启动时,动态加载器使用 ld.so.cache 中的缓存信息来定位文件。对 ld.so.conf 文件的任何更改都需要运行 ldconfig 命令来更新 /etc/ld.so.cache 文件。
如果您想了解应用程序是静态链接的,还是动态链接应用程序的依赖项是什么,您可以使用 ldd 命令。例如 ldd /usr/sbin/apache 显示以下内容
ldd /usr/sbin/apache2 linux-vdso.so.1 => (0x00007ffff85ff000) libpcre.so.3 => /lib/libpcre.so.3 (0x00007feeaf2e4000) libaprutil-1.so.0 => /usr/lib/libaprutil-1.so.0 (0x00007feeaf0c1000) libapr-1.so.0 => /usr/lib/libapr-1.so.0 (0x00007feeaee8b000) libpthread.so.0 => /lib/libpthread.so.0 (0x00007feeaec6e000) libc.so.6 => /lib/libc.so.6 (0x00007feeae8eb000) libuuid.so.1 => /lib/libuuid.so.1 (0x00007feeae6e5000) librt.so.1 => /lib/librt.so.1 (0x00007feeae4dd000) libcrypt.so.1 => /lib/libcrypt.so.1 (0x00007feeae2a4000) libdl.so.2 => /lib/libdl.so.2 (0x00007feeae09f000) libexpat.so.1 => /lib/libexpat.so.1 (0x00007feeade76000) /lib64/ld-linux-x86-64.so.2 (0x00007feeaf7ab000) |
这告诉我们 apache2 是动态链接的,并依赖于列出的库。如果缺少库,ldd 将使用“未找到”一词输出依赖项。这在排查依赖性问题时很有用。
LD_LIBRARY_PATH
有时您可能需要覆盖动态库的默认搜索路径。这可能是为了您从源代码安装的应用程序,为了测试最新版本的库,或者如果应用程序依赖于您已安装在机器上的旧版本的库。
要将库添加到搜索路径,您需要定义和导出 LD_LIBRARY_PATH 变量,如下所示
# export LD_LIBRARY_PATH=/usr/lib/:/opt/someapp/lib; |
LD_LIBRARY_PATH 是一个冒号分隔的目录列表,在 ld.so.cache 中指定的系统目录之前搜索这些目录。这允许临时覆盖在 ld.so.cache 和受信任目录中定义的库。
使用的文件、术语和实用程序
- ldd
- ldconfig
- /etc/ld.so.conf
- LD_LIBRARY_PATH