1. 函数库

1.本质:一组函数,具有相近的功能或操作同一数据结构

  • <string.h>:strcpy/strcmp/strcat/strlen/strstr/strchr/strtkk…..
  • 自定义库:<mysort.h>:bubble_sort/select_sort/quick_sort/insert_sort…..

2.作用:

  • 代码复用
  • 出现积累

3.发布形式:

  • 源码形式

    • 优点:方便使用者学习和使用
    • 缺点:保密性差、编译程序耗时、编译受平台、版本限制
  • 二进制形式:

    • 优点、缺点与上面相反

4.我们使用的函数:标准c库:/lib/x86_64-linux-gnu/libc.so.6`

2.静态库

在linux中静态库由程序ar生成,现在静态库已经不像之前那么普遍了,这主要是由于程序都在使用动态库。关于静态库的命名如下:

  • 机制:在编译程序时,复制静态库的代码片,到可执行程序中
  • 优点:将函数库中的函数本地化,寻址方便,速度快。(库函数执行效率==自定义函数执行效率)
  • 缺点:消耗系统资源大,每个使用静态库的程序,都要复制一份静态库,浪费内除。
  • 使用场景:多用于核心程序,保证时效性,可以忽略空间。
  • 静态库的命名方式:
    • 在Linux中静态库以lib作为前缀,以.a作为后缀,中间是库的名字(自己指定即可),即libxxx.a
    • 在Windows中静态库一般以lib作为前缀,以lib作为后缀,中间是库的名字(自己指定即可),即libxxx.lib

2.1生成静态库链接

生成静态库,需要先对源文件进行汇编操作(使用参数-c)得到二进制格式的目标文件(.o格式)。然后再通过ar工具将目标文件打包就可以得到静态库文件了(libxxx.a)。

使用ar工具创建静态库的时候需要三个参数:

  • 参数c:创建一个库,不管库是否存在,都将创建。

  • 参数s:创建目标文件索引,这在创建较大的库时能加快时间。

  • 参数r:在库中插入模块(替换)。默认新的成员添加在库的结尾处,如果模块名已经在库中存在,则替换同名的模块。

2.2静态库的使用

参数-l:在程序编译的时候,指定使用的库(掐头去尾)

参数-L:指定编译的时候,搜索的库的路径———–>空格空不空都可以

步骤:

  • 添加静态库的函数功能实现:分别在add.c、sub.c、mul.c文件中添加各自代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //add.c文件添加如下代码
    int add(int a, int b){
    return a+b;
    }

    //sub.c文件添加如下代码
    int sub(int a, int b){
    return a-b;
    }

    //mul.c文件添加如下代码
    int mul(int a, int b){
    return a*b;
    }
  • 创建一个调用静态库的函数:在math.c文件中添加如下程序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <stdio.h>

    int add(int, int);
    int sub(int, int);
    int mul(int, int);
    int main(int argc, char *argv[]){
    printf("%d + %d = %d\n", 10, 20, add(10,20));
    printf("%d - %d = %d\n", 10, 20, sub(10,20));
    printf("%d * %d = %d\n", 10, 20, mul(10,20));
    return 0;
    }
  • 生成静态库:

    • 将静态库要实现的功能函数生成二进制文件(.o文件):gcc -c add.c sub.c mul.c
    • 通过二进制文件生成静态库libmymath.a:ar rs libmymath.a add.o sub.o mul.o
  • 在编译程序时使用静态库:gcc math.c -L ./ -lmymath -o app

    • 解释:-L参数后面是要使用的静态库位置;-lmymath是静态库的名字(掐头去尾)

2.动态库

动态链接库是程序运行时加载的库,当动态链接库正确部署之后,运行的多个程序可以使用同一个加载到内存中的动态库,因此在Linux中动态链接库也可称之为共享库。

  • 机制:代码共享

  • 优点:节省内存(共享)、易于更新(动态链接)

  • 缺点:相较于静态库而言,函数调用速度慢(函数地址“延时绑定”)

  • 使用场景:

    • 对程序执行速度要求不是很强烈,而对系统资源有一定要求的场景
    • 更新比较频繁的程序,方式如下:
      • 停止运行程序
      • 使用新库覆盖旧库(保证新库、旧库名称一致;接口一致)
      • 重启程序
  • 动态库的命名方式:

    • 在Linux中动态库以lib作为前缀,以.so作为后缀,中间是库的名字(自己指定即可),即libxxx.so
    • 在Windows中动态库一般以lib作为前缀,以dll作为后缀,中间是库的名字(自己指定),即libxxx.dll

注意:

  • 动态库是否加载到内存,取决于“程序是否运行”
  • 动态库加载至内存的位置是不固定的

2.1生成动态链接库

生成动态链接库是直接使用gcc命令并且需要添加-fPIC(-fpic)以及-shread参数

  • -fPIC或-fpic参数:是使得gcc生成的代码是与位置无关的,也就是使用相对位置。

  • -shared参数:是告诉编译器生成一个动态链接库

2.2使用步骤

  • 生成与位置无关的目标文件:gcc -c -fPIC add.c sub.c mul.c

  • 通过目标文件生成动态库:gcc -shared -o libmymath.so add.o sub.o mul.o

  • 使用动态库生成可执行文件:gcc math.c -o app -L ./ -lmymath

  • 启动程序:./app

    • 报错原因:”动态链接器”ld-linux-x86-64.so.2搜索动态库的路径没有指定

      • 链接器:工作于gcc生成可执行文件过程中的“链接阶段”,工作结束后,生成可执行文件
      • 动态链接器:工作于可执行程序运行之后,辅助加载器负责动态库加载到内存
      1
      ./app: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory
  • 解决上述报错的基本思想:给动态链接器指定动态库路径

    • 环境变量法:export LD_LIBRARY_PATH=./lib将当前动态库所在目录,加入到环境变量中

      • 终端一旦退出,环境变量的修改无效
    • 配置文件法:将上述修改环境变量的指令,写入到~/.bashrc中

      • 每次启动终端,自动生效
      • export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib
    • 拷贝法:受程序使用libc库的启发,将自定义的libmymath.so文件拷贝到/lib 或 /user/lib目录中

      • 为了执行用户自定义程序,需要修改系统配置
    • 缓存文件法(推荐使用):通过修改配置文件,修改缓存文件,生成动态库连接器需要搜寻的新目录位置

      • 1.打开配置文件:vim /etc/ld.so.conf
      • 2.修改配置文件:将动态库的绝对路径添加到/etc/ld.so.conf文件中
      • 3.使用命令sudo ldconfig -v动态更新ld.so.cache文件(二进制文件),该文件直接影响动态连接器搜寻动态库位置