目录

一、库的概念

二、库的类型

2.1 静态库(*.a)

2.2  动态库,也叫共享库(*.so)

三、制作和使用静态库

3.1 制作静态库

3.2使用静态库

四、制作和使用动态库

4.1 制作动态库

4.2使用动态库

4.2.1静态加载

4.2.2动态加载

        4.2.2.1 编写代码

        4.2.2.1 编译代码


一、库的概念

编译一个程序为可执行文件时,需要经过四部曲 : 预处理、编译、汇编、链接

而库是二进制形式目标模块

多个目标模块(xxx.o)的集合  

当使用库时,在链接阶段可以将链接进可执行程序,同时也可以链接目标模块

 

二、库的类型

2.1 静态库(*.a)

扩展名为.a  (与动态库的区别1)

库中封装的二进制代码,在链接阶段会被复制到可执行程序的调用模块中  (与动态库的区别2)

链接后的可执行程序运行时 , 不需要静态库的支持,由于已经复制到了可执行文件中 (与动态库的区别3)

如下图为 “链接成可执行程序的过程”

 

2.2  动态库,也叫共享库(*.so)

扩展名为.so ,windows的动态库 扩展名为.dll

库中封装二进制代码,在链接阶段不会被复制到调用模块中,被嵌入到调用模块中的仅仅是被调用的函数在动态库中的相对地址,在运行时,根据这个地址动态执行动态库中的代码

链接后的可执行程序运行时 , 需要动态库支持,这意味着你的可执行程序去哪动态库也跟着去哪,否则运行不了

如下图为 “链接成可执行程序的过程”
 

 

三、制作和使用静态库

3.1 制作静态库

(1)编写源程序(制作库用的程序)

    xxx.c    xxx.h

(2)将源代码编译成目标文件

    gcc -c xxx.c -o xxx.o

(3)将目标文件打包成静态库(库名的前缀必须是lib)

    ar   -r   lib库名.a    xxx.o   yyy.o   ....

 

3.2使用静态库

1)直接法

    gcc   main.c   lib库名.a    -o    可执行文件

2)参数法

    gcc    main.c    -l库名     -L库路径   -o   可执行文件

    注:-l表示链接哪个库名,-L表示库的额外搜索路径(相对路径或者绝对路径),例如在当前目录下时用“-L.”表示,在当前目录下的lib文件夹中用“-L./lib”

3)环境变量法

    先执行命令行,添加环境变量:

            export LIBRARY_PATH=$LIBRARY_PATH:库的路径

    然后再gcc

            gcc     main.c   -l库名   -o    可执行文件

    注:环境变量 LIBRARY_PATH 记录链接时库的搜索路径

       如果希望环境变量的设置持久化,需要把设置环境变量的命令加入到文件 ~/.bashrc 中

 

 

四、制作和使用动态库

4.1 制作动态库

(1)编写源程序(制作库用的程序)

    xxx.c    xxx.h

(2)编译成目标模块

    gcc   -c    -fpic   xxx.c   -o   xxx.o

    备注: -fpic 表示 position indipendent code 未知无关代码。

(3)链接成共享库

    gcc   -shared   xxx.o   yyy.o   ....   -o   lib库名.so

 

4.2使用动态库

注意⚠️:当静态库和动态库同名,优先使用动态库

使用动态库时,分两种加载方法,分别是静态加载 和 动态加载

静态加载就是程序一运行, 就自动加载

动态加载就是程序运行中,由程序猿的代码控制加载

4.2.1静态加载

1)直接法

    gcc    mian.c    lib库名.so    -o    可执行文件

2)参数法

    gcc    main.c    -l库名     -L库路径    -o     可执行文件

3)环境变量法

     export LIBRARY_PATH=$LIBRARY_PATH:库路径

    gcc    main.c    -l库名   -o    可执行文件

    注:环境变量 LIBRARY_PATH 记录链接时库的搜索路径

       如果希望环境变量的设置持久化,需要把设置环境变量的命令加入到文件 ~/.bashrc 中

 

⚠️但是 使用了动态库的程序在运行时会去环境变量 LD_LIBRARY_PATH 记录的路径中寻找动态库来使用,如果找不到就报错  

为了使用了动态库的程序正常运行,需要将动态库的路径加入到环境变量  LD_LIBRARY_PATH 中

export    LD_LIBRARY_PATH=$LD_LIBRARY_PATH:库路径

 

4.2.2动态加载

4.2.2.1 编写代码

如果你的代码xxx.c 需要使用一个动态库,那么需要包含dlfcn.h头文件

然后依次完成下面的步骤

1)加载动态库 -------- dlopen

参数:

  • filename :        如果给的是文件名,就去系统指定的搜索路径(LD_LIBRARY_PATH)下查找加载动态库文件
  •                         如果给的是路径,直接按照路径查找加载动态库文件,不去指定路径搜索
  • flag : 加载标志
  •                         RTLD_LAZY - 延迟加载,什么时候使用动态库再去加载
  •                         RTLD_NOW - 立即加载
  • 返回值:
  •                         成功返回共享库的句柄(指针),失败返回NULL

 

2)获取函数的地址 ----- dlsym

参数:

  •         handle - 动态库的句柄(即第一步创建的句柄)
  •         symbol - 函数名

成功返回函数的地址,失败返回NULL

 

3)调用对应的函数(函数指针)

 

4)不再使用共享库卸载 ------- dlclose

    传入共享库的句柄

 

参考代码如下:

#include <stdio.h>
#include <dlfcn.h>

//函数指针类型别名p_func
typedef int (*pfunc_t)(int,int);
typedef void (*pfunc2_t)(int,int,char,int);

int main()
{
    int num = 0,num1 = 0;
    
    //1.加载动态库
    void *handle = dlopen("./lib/libmath.so",RTLD_LAZY);
    if(!handle){
        printf("dlopen:%s\n",dlerror());
        return -1;
    }

    //2.获取函数地址
    pfunc_t add = dlsym(handle,"add");
    if(!add){
        printf("dlsym:%s\n",dlerror());
        return -1;
    }

    pfunc2_t show = dlsym(handle,"show");
    if(!show){
        printf("dlsym:%s\n",dlerror());
        return -1;
    }

    //3.调用函数
    //printf("%d\n",mul(3,4));
    printf("please two num:");
    scanf("%d %d",&num,&num1);
    show(num,num1,'+',add(num,num1));


    //4.卸载共享库
    dlclose(handle);

    return 0;
}

 

 

4.2.2.1 编译代码

使用该工具编译时要链接dl库

gcc   xxx.c   -o    可执行文件   -ldl  

 

 

 

 

整理不易

点赞收藏关注喔~

Logo

更多推荐