Linux 动态链接库和静态链接库

发布时间: 更新时间: 总字数:1168 阅读时间:3m 作者: IP上海 分享 网址

本文介绍 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自动生成的共享库文件

其他文件:

  • .ko: kernel object文件(内核模块),该文件把内核的一些功能移动到内核外边,需要的时候插入内核,不需要时卸载,一般为驱动程序。达到减少内核体积的目的。参考:Linux kernel 内核模块编译、装载和卸载

概念

  • 静态链接库
    • 在链接阶段,会将汇编生成的目标文件 .o 与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接
    • 库命名规范,必须是 lib[your_library_name].alib为前缀,中间是静态库名,扩展名为.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,在其后边添加 .solibtest.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 指定其它的动态链接库位置
Home Archives Categories Tags Statistics
本文总阅读量 次 本站总访问量 次 本站总访客数