Linux共享库概述( 八 )


文件系统层次标准(FHS)讨论了在分发中应该去哪里(请参阅 ) 。 根据FHS , 大多数库应该安装在/ usr / lib中 , 但启动所需的库应该在/ lib中 , 不属于系统的库应该在/ usr / local / lib中 。
这两个文件之间没有真正的冲突; GNU标准建议开发人员使用默认的源代码 , 而FHS则建议分销商使用默认值(通常通过系统的软件包管理系统来选择覆盖源代码默认值) 。 在实践中 , 这很好地工作:您下载的“最新”(可能是buggy!)源代码自动安装在“本地”目录(/ usr / local) , 一旦该代码已经成熟 , 软件包管理器可以轻松地覆盖默认值 , 以将代码放置在标准的发行版中 。 请注意 , 如果您的库调用只能通过库调用的程序 , 则应将这些程序放在/ usr / local / libexec(在/ usr / libexec中) 。 一个复杂的情况是 , Red Hat派生的系统在搜索库时默认不包括/ usr / local / lib; 请参阅下面关于/etc/ld.so.conf的讨论 。 其他标准库位置包括用于X-windows的/ usr / X11R6 / lib 。 请注意 , / lib / security用于PAM模块 , 但通常会作为DL库加载(下面也将讨论) 。
3.2 如何使用库在基于GNU glibc的系统(包括所有Linux系统)上 , 启动ELF二进制可执行文件会自动导致程序加载器被加载并运行 。 在Linux系统上 , 此加载程序名为/lib/ld-linux.so.X(其中X是版本号) 。 反过来 , 这个装载器可以找到并加载程序使用的所有其他共享库 。
要搜索的目录列表存储在文件/etc/ld.so.conf中 。 许多Red Hat派生的发行版通常不会在/etc/ld.so.conf文件中包含/ usr / local / lib 。 我认为这是一个错误 , 并在/etc/ld.so.conf中添加/ usr / local / lib是在Red Hat派生系统上运行许多程序所需的常见“修复” 。
如果您只想覆盖库中的一些函数 , 但保留库的其余部分 , 则可以在/etc/ld.so.preload中输入覆盖库(.o文件)的名称 。 这些“预加载”库将优先于标准集 。 此预加载文件通常用于紧急补丁; 分发通常不会在交付时包含这样的文件 。
在程序启动时搜索所有这些目录将是非常低效的 , 因此实际使用了缓存安排 。 程序ldconfig(8)默认读入/etc/ld.so.conf文件 , 在动态链接目录中设置适当的符号链接(因此它们将遵循标准约定) , 然后将缓存写入/ etc / ld.so.cache , 然后被其他程序使用 。 这极大地加快了访问图书馆的速度 。 这意味着 , 每当添加一个DLL , 当一个DLL被删除或一组DLL目录发生变化时 , ldconfig必须运行; 运行ldconfig通常是软件包管理器在安装库时执行的步骤之一 。 在启动时 , 动态加载器实际上使用文件/etc/ld.so.cache , 然后加载它需要的库 。
顺便说一句 , FreeBSD对这个缓存使用稍微不同的文件名 。 在FreeBSD中 , ELF缓存为/var/run/ld-elf.so.hints , a.out缓存为/var/run/ld.so.hints 。 这些仍然由ldconfig(8)更新 , 所以这个位置的差异只能在几个异乎寻常的情况下重要 。
环境变量各种环境变量可以控制此过程 , 并且有一些环境变量允许您覆盖此过程 。
LD_LIBRARY_PATH您可以临时替换不同的库进行此特定执行 。 在Linux中 , 环境变量LD_LIBRARY_PATH是一个冒号分隔的目录库 , 首先要在库文件的标准目录集之前进行搜索; 当调试新库或为特殊目的使用非标准库时 , 这非常有用 。 环境变量LD_PRELOAD列出了覆盖标准集的函数的共享库 , 就像/etc/ld.so.preload一样 。 这些由加载器/lib/ld-linux.so实现 。 我应该注意 , 虽然LD_LIBRARY_PATH适用于许多类Unix系统 , 但它并不适用; 例如 , 此功能在HP-UX上可用 , 但作为环境变量SHLIB_PATH , 在AIX上 , 此功能是通过变量LIBPATH(具有相同的语法 ,
LD_LIBRARY_PATH适用于开发和测试 , 但不应由正常用户正常使用的安装过程进行修改; 请参阅~barr/ldpath.html 上的“为什么LD_LIBRARY_PATH为坏” , 以 了解为什么 。 但它仍然可用于开发或测试 , 以及解决不能解决的问题 。 如果您不想设置LD_LIBRARY_PATH环境变量 , 那么在Linux上 , 您甚至可以直接调用程序加载器并传递参数 。 例如 , 以下将使用给定的PATH而不是环境变量LD_LIBRARY_PATH的内容 , 并运行给定的可执行文件: