本文介绍 Linux 动态和静态链接库,并通过demo示例,介绍动态链接库和静态链接库的工作过程和原理。
文件格式
.h
: C 语言头文件,包含了 C 函数声明、宏定义、结构体定义等内容.c
: C 语言程序文件,内含函数实现,变量定义等内容.o
: 目标(object)文件,一个 *.c
或 *.cpp
文件编译生产一个 .o
文件.a
: archive 归档包,一个或多个 *.o
打包生产,实现静态连接库
功能,即 static mode
,多个 *.a
可以链接生成一个可执行文件.so
: shared object 共享库文件,实现动态链接库
功能。和 windows的dll
差不多,使用时才载入.la
: libtool archive 文件,是libtool自动生成的共享库文件
其他文件:
概念
- 静态链接库
- 在链接阶段,会将汇编生成的目标文件
.o
与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接 - 库命名规范,必须是
lib[your_library_name].a
,lib
为前缀,中间是静态库名,扩展名为.a
- 动态链接库
- 是一种不可执行的二进制程序文件,它允许程序共享执行特殊任务所必需的代码和其他资源。Linux 中以
*.so
结尾
- 查看工具
示例
编译相关工具:
yum install -y gcc binutils
# 目录初始化
[root@xiexianbin_cn ~]# mkdir ldd-demo
[root@xiexianbin_cn ~]# cd ldd-demo/
# 文件内容
[root@xiexianbin_cn ldd-demo]# cat test.h
void print();
[root@xiexianbin_cn ldd-demo]# cat test.c
#include <stdio.h>
#include "test.h"
void print()
{
printf("hello world!\n");
}
[root@xiexianbin_cn ldd-demo]# cat main.c
#include "test.h"
int main()
{
print();
return 0;
}
# gcc 编译
[root@xiexianbin_cn ldd-demo]# ls
main.c test.c test.h
[root@xiexianbin_cn ldd-demo]# gcc -c main.c test.c
[root@xiexianbin_cn ldd-demo]# gcc main.o test.o
[root@xiexianbin_cn ldd-demo]# ls
a.out main.c main.o test.c test.h test.o
# 执行
[root@xiexianbin_cn ldd-demo]# ./a.out
hello world!
# 使用 ldd 查看 a.out
[root@xiexianbin_cn ldd-demo]# ldd a.out
linux-vdso.so.1 => (0x00007ffc92fc3000)
libc.so.6 => /lib64/libc.so.6 (0x00007fb6b0c02000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb6b0fcf000)
[root@xiexianbin_cn ldd-demo]# ldd *
a.out
依赖于 libc.so.6
,路径为 /lib/libc.so.6
。
静态库
[root@xiexianbin_cn ldd-demo]# ls
main.c test.c test.h
[root@xiexianbin_cn ldd-demo]# gcc -c test.c
[root@xiexianbin_cn ldd-demo]# ls
main.c test.c test.h test.o
[root@xiexianbin_cn ldd-demo]# ar rcs libtest.a test.o
[root@xiexianbin_cn ldd-demo]# ls
libtest.a main.c test.c test.h test.o
[root@xiexianbin_cn ldd-demo]# gcc main.c -L. -ltest
[root@xiexianbin_cn ldd-demo]# ls
a.out libtest.a main.c test.c test.h test.o
[root@xiexianbin_cn ldd-demo]# ./a.out
hello world!
[root@xiexianbin_cn ldd-demo]# ldd a.out
linux-vdso.so.1 => (0x00007ffc8c9fa000)
libc.so.6 => /lib64/libc.so.6 (0x00007f5f4647a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5f46847000)
与上面的基本一样。
动态链接库
[root@xiexianbin_cn ldd-demo]# ls
main.c test.c test.h
[root@xiexianbin_cn ldd-demo]# gcc test.c -shared -fPIC -o libtest.so
[root@xiexianbin_cn ldd-demo]# ls
libtest.so main.c test.c test.h
[root@xiexianbin_cn ldd-demo]# gcc main.c -L. -ltest
[root@xiexianbin_cn ldd-demo]# ls
a.out libtest.so main.c test.c test.h
[root@xiexianbin_cn ldd-demo]# ./a.out
hello world!
[root@xiexianbin_cn ldd-demo]# ./a.out
hello world!
# a.out 依赖 libtest.so 库
[root@xiexianbin_cn ldd-demo]# ldd a.out
linux-vdso.so.1 => (0x00007ffc509ce000)
libtest.so (0x00007fd80275b000)
libc.so.6 => /lib64/libc.so.6 (0x00007fd80238e000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd80295d000)
[root@xiexianbin_cn ldd-demo]# ldd libtest.so
linux-vdso.so.1 => (0x00007ffc1ad75000)
libc.so.6 => /lib64/libc.so.6 (0x00007fe1e6141000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe1e6710000)
说明:
- 命令:gcc test.c -shared -fPIC -o libtest.so
- -shared: 编译成的文件为
动态链接库
,不使用该选项相当于可执行文件 - -fPIC: PIC(Position-Independent Code)编译为位置独立的代码,不用此选项是编译的代码是与位置相关的
- 命令:gcc main.c -L. -ltest
- -L.: 表示链接的文件在当前目录下
- -ltest: 链接的文件名
gcc
会自动为其前面添加 lib
,在其后边添加 .so
即 libtest.so
若将 libtest.so
移动到 /tmp
目录
[root@xiexianbin_cn ldd-demo]# mv libtest.so /tmp/
[root@xiexianbin_cn ldd-demo]# ldd a.out
linux-vdso.so.1 => (0x00007fff8fb00000)
libtest.so => not found
libc.so.6 => /lib64/libc.so.6 (0x00007fb52c0bf000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb52c48c000)
[root@xiexianbin_cn ldd-demo]# ./a.out
./a.out: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory
可以看到 libtest.so => not found
,执行 a.out
失败。将 libtest.so
移动到 /usr/lib64/
目录也可以正常使用:
[root@xiexianbin_cn ldd-demo]# mv /tmp/libtest.so /usr/lib64/
[root@xiexianbin_cn ldd-demo]# ./a.out
hello world!
[root@xiexianbin_cn ldd-demo]# ldd a.out
linux-vdso.so.1 => (0x00007fffe87f4000)
libtest.so => /lib64/libtest.so (0x00007f808dc89000)
libc.so.6 => /lib64/libc.so.6 (0x00007f808d8bc000)
/lib64/ld-linux-x86-64.so.2 (0x00007f808de8b000)
说明:
/usr/lib/:/usr/lib64/:/lib/:/lib64/
为默认动态链接库的目录,可以通过环境变量 LD_LIBRARY_PATH
指定其它的动态链接库位置