一、公约
1. 库的命名习惯
一个linux DLL 有三个不同名字的文件组成
soname 文件
每当链接库接口改变时都递增版本号。soname 文件其实只是一个符号链接而已,指向他的real name 文件。
real name 文件
发行号是可选的。该文件包含实际代码。
linker name 文件
编译器以这个名字来请求指定的链接库。
当程序在内部列出所需要的链接库时,仅仅使用 soname。当你创建一个链接库时,使用 real name。安装一个新的链接库时,把它复制到一个DLL文件夹里,然后运行程序 ldconfig(8)。ldconfig 检查存在的 real name 文件,并且创建指向它的符号链接 soname 文件。ldconfig 还做一件事情就是建立 cache 文件 /etc/ld.so.cache
ldconfig 不会创建 linker name 文件,但是一般性 linker name 文件在安装链接库的时候创建。linker name 文件也只是一个符号链接,指向最新的 soname 文件或 real name 文件。建议指向 soname 文件,因为当你更新库以后,在编译器链接的时候,一般总是想使用新的库。
2. 库的放置
DLL 必须放置在文件系统的指定位置。多数开源软件遵守GNU 标准:当分发源代码的时候,库默认安装在 /usr/local/lib,命令安装在 /usr/local/bin。该标准还定义了如何重写这些默认标准以及如何调用安装程序。
Filesystem Hierarchy Standard(FHS) 规定:多数库应安装在 /usr/lib,启动时需要的库安装在 /lib,非系统库应安装在 /usr/local/lib
GNU 标准是针对开发人员的,FHS 是针对发行者的。
二、 库是如何被使用的
在基于 GNU glibc 的系统上,包括所有 linux 系统,ELF 可执行二进制文件的运行自动导致程序加载器被加载并且运行。在 linux 下,加载器是 /lib/ld-linux.so.X(X是版本号)。然后加载器搜索、加载程序所要使用的动态链接库。
被搜索的文件夹列表保存在文件 /etc/ld.so.conf 里。
在程序启动的时候搜索这些文件夹是很没有效率的,所以实际上使用缓存。ldconfig(8) 默认读取 /etc/ld.so.conf 文件,在 DLL 文件夹里创建合适的符号链接,在 /etc/ld.so.cache 里写入一个缓存。缓存大大加速了库的读取。所以,当一个 DLL 被添加、删除时,或DLL文件夹被改变时都需要运行 ldconfig 程序,当安装了一个新的 DLL 时,由软件包管理器自动运行 ldconfig。当程序启动时,装载器实际使用的是缓存。
环境变量
LD_LIBRARY_PATH
该变量里所指定的文件夹将会首先被搜索,然后才会搜索默认的 DLL 文件夹。该变量对开发和测试比较有用,但不应该为了给普通用户使用而设置。如果你不想设置该变量,在 linux 下你可以直接调用程序加载器,比如,你可以传递 PATH 参数给加载器代替该变量来运行程序:
不带参数执行加载器,可以得到更多帮助。但是,不要这样执行程序,仅供调试时使用。
LD_DEBUG
看名字就知道,是供调试使用的。该变量是dl*函数的开关,用来显示正在做的事情的详细信息。可以取值为:
files | 显示so文件的加载顺序 |
bindings | 显示关于符号帮定的信息 |
libs | 显示库搜索路径的信息 |
versions | 显示版本依赖的信息 |
help | 使用该值运行程序将会显示可用的选项 |
三、创建动态链接库
首先用 -fpic 或 -fPIC 选项创建要放入 DLL 中的目标文件。使用该选项生成的代码是位置无关的代码(DLL的必要条件)。使用 gcc 的 -Wl 选项传递 soname 参数给链接器。-Wl 选项里不能有未转义的 whitespace。使用如下命令创建 DLL:
举个例子:
该例子首先创建了两个与位置无关的目标文件 a.o、b.o,然后生成了一个包含两者的 DLL。注意:-g 选项使代码包含调试信息,-Wall 选项用来产生警告,两者并不是创建 DLL 必须的,但是建议加上。
不要 strip 所生成的 DLL,或使用编译器参数 -fomit-frame-pointer,这样做将会无法使用调试器。
-fPIC 选项总是可以使用,但生成的代码比使用 -fpic 的要大。-fpic 选项生成的代码比较小、快,但是有平台相关的限制,当创建 DLL 时,链接器将会告诉你是否符合限制。
链接器还有一个有用的选项 -rpath,可以用来指定程序在运行时搜索DLL时的路径,使用 gcc 时可以这样传递参数给链接器:
如果你使用了这个选项,就不用考虑 LD_LIBRARY_PATH 这个环境变量了。
四、安装、使用动态链接库
1.安装在标准位置
最简单的安装方式是复制 DLL 到一个标准的 DLL 文件夹(/usr/lib等)并且运行 ldconfig(8),然后手动创建 linker name 符号链接。
2.安装在非标准位置
下面的命令将会在指定的文件夹里创建适当的 soname 符号链接。
然后手动创建 linker name 文件指向 soname 文件。
编译程序的时候使用 -l、-L 参数指定需要链接的库和库所在的位置。
除非使用 -rpath 参数指定过运行时库搜索路径,否则在运行时也必须指定。(所以在eclipse中运行称找不到liqwt.so.5)
比如可以使用如下命令添加当前工作目录到 LD_LIBRARY_PATH 来运行程序:
ldd 命令可以用来查看程序的依赖,例如: