菜单

Linux下的静态库、动态库和动态加载库

2020年3月1日 - 计算机服务器

Linux库类型

Linux下可以创建两种类型的库:

  1. 静态库(.a)金沙国际唯一官网,: 在链接期间被应用程序直接链接进可执行文件
  2. 动态链接库(.so): 动态库还分为两种用法: a)
    应用程序运行期间链接动态库,但是在编译期间声明动态库的存在,也就是说这种动态库必须在编译时对编译器可见,但编译器却不将此种库编译进可执行文件; b)
    在运行期间,动态加载和卸载的库,使用动态加载方法加载。这种库的形式跟动态链接没有本质区别,区别是在调用时,是由用户程序决定何时链接的,而不是由系统链接器自动链接

库文件的存在极大的提高了 C/C++
程序的复用性,本文简单介绍如何生成、使用它们。

命名约定

库需要以lib作为开头,而在指定链接命令行参数时,却无需包含开头和扩展名,例如:

gcc src-file.c -lm -lpthread

这个例子中,链接了libmath.alibpthread.a

命名约定:
我们一般对库文件约定以 lib 开头,动态库文件一般以 .so(*nix)或
.dll(Windows) 结尾,静态库文件一般以 .a(*nix)或
.lib(Windows) 结尾。

静态库(.a)

生成静态库的方法如下:

.a文件与windows下的.lib是相同的概念。

动态库还分为两种用法:

动态库(.so)

生成动态库的方法如下:

编译object文件时使用-fPIC选项:

gcc -Wall -fPIC -c *.c

这个选项的目的是让编译器生成地址无关(position
independent)的代码,这是因为,动态库是在运行期间链接的,变量和函数的偏移量是事先不知道的,需要链接以后根据offset进行地址重定向。

使用-shared链接

gcc -shared -Wl,-soname,libctest.so.1 -o libctest.so.1.0 *.o

-shared选项是让动态库得以在运行期间被动态链接;-Wl,options是设置传递给ld(链接器)的参数,在上面的例子中,当链接器在链接.o时会执行ld -soname ibctest.so.1

创建软链

上面的命令将最终输出一个动态库libctest.so.1.0,而出于习惯,会创建两个软链:

mv libctest.so.1.0 /opt/lib
ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so.1
ln -sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so

libctest.so用于在编译期间使用-lctest让编译器找到动态库,而libctest.so.1用于在运行期间链接

gcc -Wall -I/path/to/include-files -L/path/to/libraries prog.c -lctest -o prog
  1. 在编译期间声明动态库的存在,运行时由系统链接器自动链接
  2. 在运行期间动态加载和卸载,由用户程序决定何时链接

查看依赖

使用ldd命令来查看程序对动态库的依赖。例如:

ldd prog

libctest.so.1 => /opt/lib/libctest.so.1 (0x00002aaaaaaac000)
libc.so.6 => /lib64/tls/libc.so.6 (0x0000003aa4e00000)
/lib64/ld-linux-x86-64.so.2 (0x0000003aa4c00000)

下面我们以 Linux 为例,Windows 的用法与此有所不同,但思路大同小异。

obj文件

obj文件的格式和组成可能是系统差异性的一大体现,比如windows下的PElinux和一些unix下的elfmacosmach-oaix下的xcoff

查看obj文件的符号表信息,可以通过nm objdump readelf等方法。

生成和使用静态链接库

将库源码编译成目标文件:

$ gcc -c struct.c [-o struct.o]

打包库文件:

$ ar cr libstruct.a struct.o # 注意参数顺序不能错

这里的 artar 类似,是一种打包工具。

可以使用 $ ar -t libstruct.a 命令 检查包含哪些 .o 文件。

构建符号表:

$ ranlib libstruct.a

这个命令不是必须的,是因为部分 ar 的实现集成了该功能,此时的 ranlib
就是一个空壳命令。

链接静态库,生成可执行文件:

$ gcc main.c -static -L . -lstruct -o main

因为我们约定库文件以 lib 开头,所以这里可以省掉它。

设置库文件的环境路径:

  1. 定义 LD_LIBRARY_PATH 环境变量,添加动态库文件的路径。
  2. 把库路径添加到 ld.so.conf 文件中,然后用 ldconfig 加载。
  3. 使用 ldconfig <path-to-so-directory> 临时加载。

编译时,如果出现重名的动态库和静态库,优先使用动态库。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图