0%

Linux中动态库和静态库

Linux基础(8):Linux中静态库和动态库

静态库和动态库的制作、 使用、 处理动态库链接问题等

库文件,简单说就是源文件(.c/.cpp)转换为二进制文件。

采用库文件的目的

  • 简化工程的源文件数量,生成库文件之后是不需要再去维护的。
  • 开发者处于保护知识产权的目的

拥有库文件之后,同时还要有库的API声明(头文件),添加头文件到项目中,使用其API

静态库

  • 静态库的生成

    • 生成汇编文件
    1
    2
    #得到-o的汇编文件
    gao@gao-VirtualBox:~/桌面/test/d$ gcc -c add.c sub.c
    • 打包汇编文件
    1
    2
    #rcs参数必须带,库的命名遵循libXXX.a的规则
    gao@gao-VirtualBox:~/桌面/test/d$ ar rcs libcal.a add.o sub.o
    • 将声明文件和库文件放在一起

    此示例中,是将head.h和libcal.a文件共同发布给使用者

    操作示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#准备相关文件,head.h   add.c  sub.c  main.c  
#head.h中声明add函数,sub函数。
#add.c&sub.c中实现相关功能
#main.c中调用add和sub函数

#head.h文件
gao@gao-VirtualBox:~/桌面/test/d$ cat head.h
#ifndef _HEAD_H
#define _HEAD_H

//加法
int add(int a, int b);

//减法
int sub(int a, int b);
#endif

#add.c文件
gao@gao-VirtualBox:~/桌面/test/d$ cat add.c
#include <stdio.h>
#include "head.h"

int add(int a, int b)
{
return a+b;
}

#sub.c文件
gao@gao-VirtualBox:~/桌面/test/d$ cat sub.c
#include <stdio.h>
#include "head.h"

int sub(int a, int b)
{
return a-b;
}

#main.c文件
gao@gao-VirtualBox:~/桌面/test/d$ cat main.c
#include <stdio.h>
#include "head.h"

int main()
{
int a= 10;
int b= 10;

printf("a+b=%d\n",add(a, b));
printf("a-b=%d\n",sub(a, b));
return 0;
}
gao@gao-VirtualBox:~/桌面/test/d$ tree
.
├── add.c
├── head.h
├── main.c
└── sub.c

0 directories, 4 files

#执行汇编指令 -c
gao@gao-VirtualBox:~/桌面/test/d$ gcc -c add.c sub.c
gao@gao-VirtualBox:~/桌面/test/d$ ls
add.c add.o cal head.h main.c sub.c sub.o

#打包得到静态库
gao@gao-VirtualBox:~/桌面/test/d$ ar rcs libcal.a add.o sub.o
gao@gao-VirtualBox:~/桌面/test/d$ ls
add.c add.o cal head.h libcal.a main.c sub.c sub.o
  • 静态库的使用

    • 关键语法
    1
    2
    3
    #gcc命令下指定库文件地址, 指定库文件名称(名称掐头去尾)
    gao@gao-VirtualBox:~/桌面/test/e$ gcc main.c -o cal -L ./ -l cal
    # -L指定搜索库的路径, -l指定库的名称

    操作示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #将发布的静态库文件和头文件放在一个文件夹中,再放入需要执行的程序main.c
    gao@gao-VirtualBox:~/桌面/test/e$ ls
    head.h libcal.a main.c

    #尝试直接编译程序,会报找不到函数实现的错误
    gao@gao-VirtualBox:~/桌面/test/e$ gcc main.c -o cal
    /usr/bin/ld: /tmp/ccTynhSq.o: in function `main':
    main.c:(.text+0x25): undefined reference to `add'
    /usr/bin/ld: main.c:(.text+0x47): undefined reference to `sub'
    collect2: error: ld returned 1 exit status

    #gcc命令下指定库文件地址, 指定库文件名称(名称掐头去尾)
    gao@gao-VirtualBox:~/桌面/test/e$ gcc main.c -o cal -L ./ -l cal
    gao@gao-VirtualBox:~/桌面/test/e$ ls
    cal head.h libcal.a main.c

    #顺利生成并执行
    gao@gao-VirtualBox:~/桌面/test/e$ ./cal
    a+b=20
    a-b=0

动态库

  • 动态库的制作&发布

    基本语法

    同静态库一样,依然是先准备需要发布的文件

    之后执行汇编,再进行打包操作

    关键点

    汇编时加入-fpic参数,表明与位置无关,之后才能进一步生成动态库

    打包时,-shared参数,表明是动态库类型

    linux下动态库,统一格式libXXX.so

    1
    2
    3
    4
    5
    #汇编命令
    gao@gao-VirtualBox:~/桌面/test/f/d$ gcc -c -fpic add.c sub.c

    #打包操作
    gao@gao-VirtualBox:~/桌面/test/f/d$ gcc -shared add.o sub.o -o -libcal.so

    操作示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    gao@gao-VirtualBox:~/桌面/test/f/d$ ls
    add.c head.h main.c sub.c
    #执行汇编后
    gao@gao-VirtualBox:~/桌面/test/f/d$ gcc -c -fpic add.c sub.c
    gao@gao-VirtualBox:~/桌面/test/f/d$ ls
    add.c add.o head.h main.c sub.c sub.o
    #执行打包操作后
    gao@gao-VirtualBox:~/桌面/test/f/d$ gcc -shared add.o sub.o -o -libcal.so
    gao@gao-VirtualBox:~/桌面/test/f/d$ ls
    add.c add.o head.h libcal.so main.c sub.c sub.o

    发布时将head.h和libcal.so两个文件均发布出去.

  • 动态库的调用方式

    基本语法

    编译使用含有动态库的文件时,同静态库类似,需要指明库的路径以及名称

    1
    2
    3
    4
    5
    6
    7
    gao@gao-VirtualBox:~/桌面/test/f/d$ gcc main.c -o cal -L./ -l cal
    gao@gao-VirtualBox:~/桌面/test/f/d$ ls
    add.c add.o cal head.h libcal.so main.c sub.c sub

    #但是实际运行时,动态库会报错
    gao@gao-VirtualBox:~/桌面/test/f/d$ ./cal
    ./cal: error while loading shared libraries: libcal.so: cannot open shared object file: No such file or directory

处理动态库链接不到问题

常用的办法

首先明确,链接时是由动态链接器来寻找库文件,其搜寻路径如下

1
2
3
4
1.可执行文件内部的 DT_RPATH 段
2.系统的环境变量 LD_LIBRARY_PATH
3.系统动态库的缓存文件 /etc/ld.so.cache
4.存储动态库 / 静态库的系统目录 /lib/, /usr/lib 等

所以要保证,我们的库文件能在这四个途径之一中被动态链接器找到。

丙哥的文章中(链接附于文末)提供了三种方案,针对2.3.4的途径进行设置,我偷个懒仅以第三种方案为例来进行测试。实际情况中,这种方式较差,软链接要优于该方案,因为软链接在库更新后,是无需变动的,而拷贝方案则需要重新拷贝获得最新库文件。

操作示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#采用拷贝库文件的方式来解决,面向途径四来修改
gao@gao-VirtualBox:~/桌面/test/f/d$ ./cal
./cal: error while loading shared libraries: libcal.so: cannot open shared object file: No such file or directory
gao@gao-VirtualBox:~/桌面/test/f/d$ cp ./libcal.so /usr/lib/libcal.so
cp: 无法创建普通文件'/usr/lib/libcal.so': 权限不够
gao@gao-VirtualBox:~/桌面/test/f/d$ sudo cp ./libcal.so /usr/lib/libcal.so
[sudo] gao 的密码:

#实际执行可运行程序前,先用ldd命令,查看动态库是否已经得到地址。若显示not found 则需要更改配置
gao@gao-VirtualBox:~/桌面/test/f/d$ ldd cal
linux-vdso.so.1 (0x00007ffeccf6e000)
libcal.so => /lib/libcal.so (0x00007fdf8d77e000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdf8d58c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fdf8d79b000)

#修改后,成功运行
gao@gao-VirtualBox:~/桌面/test/f/d$ ./cal
a+b=20
a-b=0

优缺点

  • 静态库

优点

1
2
1.直接封装进程序,无需额外的库文件,移植方便
2.相比较于动态库,加载速度快

缺点

1
2
1.多个程序之间都利用该静态库时,都要保存一份代码,空间浪费
2.当库文件更新,项目需要重新编译,生成最新的程序,时间浪费
  • 动态库

优点

1
2
1.多个文件同时共享,节省空间资源
2.程序运行时被加载,更新库文件无需重新编译

缺点

1
2
1.运行时被加载,速度相较于静态库慢
2.发布程序时,需要额外发布动态库文件,配合使用。

感谢丙哥:https://subingwen.cn/linux/library/