• Linux下动态库和静态库制作与调用


    Linux下动态库和静态库制作与调用

    1.动态库和静态库简介

      静态库是指在应用中,有一些公共代码需要反复使用,就把这些代码编译为“库”文件;在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中。这种库称为其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。
      动态库又称动态链接库英文为DLL,是指DynamicLinkLibrary 的缩写形式,DLL是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件。动态链接提供了一种方法,使进程可以调用不属于其可执行代码的函数。
      静态库:在编译的时候加载生成目标文件,在运行时不用加载库,在运行时对库没有依赖性。
      动态库:在目标文件运行时加载,对库有依赖性。

     1.1 Linux下动态库和静态库命令方式

      动态库命名方式:libxxx.so。其中so是shared objecd的缩写,即可以共享的目标文件,lib为库的固定格式,xxx为库名称,.so为动态库后缀。
      动态库命名方式:libxxx.a xxx静态库名称。Linux 上的静态库,其实是目标文件的归档文件。

     1.2 编译生成共享库示例

      命令:gcc -fPIC -shared -o libxxx.so xxx.c
      此过程分为编译和链接两部分,-fPIC是编译选项,PIC表示要生成位置无关的代码,这是动态库的特性,-shared是链接选项,告诉gcc生成动态库而不是可执行文件。
      上述命令等同于:
      gcc -fPIC -c xxx.c
      gcc -shared -o libxxx.so xxx.o
      如下代码为例实现动态库编译与调用:
    在这里插入图片描述

    [wbyq@wbyq shared]$ gcc -fPIC -shared -o libmyfile.so ./src/*.c -I./include
    
    • 1

      gcc -I  指定头文路径

     1.3 动态库调用

    [wbyq@wbyq shared]$ gcc main.c -Iinclude -lmyfile -L./lib
    
    • 1

     gcc -L  指定动态库路径
     gcc -l  指定动态库名字

     1.4 程序运行

    [wbyq@wbyq shared]$ ./a.out 
    ./a.out: error while loading shared libraries: libmyfile.so: cannot open shared object file: No such file or directory
    
    • 1
    • 2

      错误原因:
      系统动态库默认搜索路径: /lib 和 /usr/lib
      解决办法1:将libmyfile.so 拷贝到/usr/lib或者/lib目录下。
      解决办法2:修改系统环境变量,动态库环境变量:LD_LIBRARY_PATH
      修改环境变量示例:

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/mnt/hgfs/ubuntu/shared/lib
    
    • 1

      注意:在命令行修改环境变量只对当前终端有效。
      解决办法2:修改系统启动文件
      Ubuntu下开机普通用户启动文件:~/.bashrc ~/.profile
      管理员用户:/.profile
      修改~/.bashrc文件:
    在这里插入图片描述
      同步文件:source ~/.bashrc

    2 linux静态库创建与调用

     2.1 linux静态库的命令规则

      静态库libxxx.a   xxx静态库名称。Linux 上的静态库,其实是目标文件的归档文件。

     2.2 linux静态库创建步骤

      (1)编写源文件,通过gcc -c生成目标文件。
      (2)用ar归档目标文件,生成静态库。
      (3)配合静态库,写一个使用静态库中函数的头文件。
      (4).使用静态库时,在源码中包含对应头文件,链接是记得链接自己的库。

     2.3 生成静态库

    [wbyq@wbyq shared]$ gcc -c src/*.c -Iinclude  #生成 .o文件
    [wbyq@wbyq shared]$ ar crv -o ./lib/libmyfile2.a ./*.o #生成静态库
    a - ./my_cat.o
    a - ./my_cp.o
    a - ./my_du.o
    
    • 1
    • 2
    • 3
    • 4
    • 5

     2.4 调用静态库和查看动态库信息

    [wbyq@wbyq shared]$ ar t ./lib/libmyfile2.a  #查看静态库信息
    my_cat.o
    my_cp.o
    my_du.o
    [wbyq@wbyq shared]$ gcc main.c -L./lib -lmyfile2 -o app -Iinclude #调用静态
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.gcc编译器常用选项

     3.1 gcc基本用法

      使用 gcc编译器的时候,我们必须给出一系列必要的调用参数和文件名称。 GCC 编译器的调用参数大约有100 多个,这里只介绍其中最基本、最常用的参数。
      gcc 最基本用法:gcc [参数] [文件名称]

     3.2 常用参数

      -c 只编译:不链接成为可执行文件,编译器只是由输入的.c 等源代码文件生成.o 为后缀的目标文件,通常用于编译不包含主程序的子程序文件。
      -o output_filename:确定输出文件的名称为 output_filename,同时这个名称不能和源文件同名。如果不给出这个选项, gcc 就给出预设的可执行文件 a.out。
      -g:产生符号调试工具(GNU 的 gdb)所必要的符号信息,要想对源代码进行调试,我们就必须加入这个选项。
      -O:对程序进行优化编译、链接,采用这个选项,整个源代码会在编译、链接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、链接的速度就相应地要慢一些。
      -O2:比-O 更好的优化编译、链接,当然整个编译、链接过程会更慢。
      -E:仅执行编译预处理;
      -S:将 C 代码转换为汇编代码;

     3.3 编译时指定库文件和头文件路径

    -L:指定动态库路径(可以指定多个路径)。
      示例: gcc test.c -o app -L/usr/lib -L ./lib
    -I:指定头文件存放的路径(可以指定多个路径)。
      示例: gcc test.c -I ./ -I /include
    -l:指定库名称(可以指定多个路径)。
      示例: gcc test.c -l my_test -l func

    4.linux下采用dlopen调用动态库

     4.1 dlopen调用动态库意义

      为了使程序方便扩展,具备通用性,可以采用插件形式。采用异步事件驱动模型,保证主程序逻辑不变,将各个业务已动态链接库的形式加载进来,这就是所谓的插件。 linux 提供了加载和处理动态链接库的系统调用,非常方便。
      生成动态库:gcc -fPIC -shared libxxx.so -o xxx.c

     4.2 dlopen系列函数介绍

    #include
    void *dlopen(const char *filename, int flags);
    函数功能:打开动态库
    形参:filename --动态库路径+名字 例:./lib/libmyfile.so
       flags --RTLD_LAZY使用时解析(暂缓解析)
       RTLD_NOW --立刻解析
    返回值: handle --成功返回库引用信息,失败返回NULL

    int dlclose(void *handle);
    函数功能:关闭动态库
    形参:handle --dlopen函数返回值

    void *dlsym(void handle, const charsymbol);
    函数功能:
    符号解析
    形参:handle --dlopen函数返回值
       symbol --要解析的符号
    返回值:成功返回符号地址,
        失败返回NULL

    char *dlerror(void); //打印错误信息

      注意:调用dlopen时需要通过-ldl指定动态库名字

     4.3函数解析示例

    #include "./include/my_file.h"
    #include 
    #include 
    int main()
    {
        int (*p)(const char *);//定义一个函数指针
    
        /*打开动态库*/
        void *handle=dlopen("./lib/libmyfile.so",RTLD_LAZY);
        if(handle==NULL)
        {
            printf("动态库解析失败%s\n",dlerror());//打印错误信息
            return 0;
        }
        /*符号解析*/
        p=dlsym(handle,"my_cat");
        int res=p("main.c");
        printf("res=%d\n",res);
    
        p=dlsym(handle,"my_du");
        p("main.c");
        //typedef unsigned int u32;
        typedef int (*my_cp)(const char *,const char *);//my_cp表示函数指针类型
        my_cp test;//定义函数指针变量
        test=dlsym(handle,"my_cp");
        test("main.c","test.c");
    
        dlclose(handle);//关闭动态库
    }
    
    • 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

     4.4变量解析示例

    #include "./include/my_file.h"
    #include 
    #include 
    int main()
    {
        int (*p)(const char *);//定义一个函数指针
        /*打开动态库*/
        void *handle=dlopen("./lib/libmyfile.so",RTLD_LAZY);
        if(handle==NULL)
        {
            printf("动态库解析失败%s\n",dlerror());//打印错误信息
            return 0;
        }
        /*符号解析*/
        p=dlsym(handle,"my_du");
        p("main.c");
        printf("-----------------------------------\n");
        /*解析变量*/
        int *p2;
        p2=dlsym(handle,"data");
        printf("*p2=%d\n",*p2);
        *p2=300;
        p("main.c");
        dlclose(handle);//关闭动态库
    }
    
    • 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
  • 相关阅读:
    Java8中的Stream流
    Linux ARM平台开发系列讲解(Linux并发与竞争) 3.1 Linux并发与竞争概述
    动态内存分配【C语言】
    《idea 骚操作》
    Web自动化测试-掌握selenium工具用法,使用WebDriver测试Chrome/FireFox网页(Java
    Azkaban
    【Shell篇<Ⅲ>】——shell函数、字符串的处理
    当中国走进全球化的“深水区”,亚马逊云科技解码云时代的中国式跃升
    【数据结构】树
    再次安装pytorch
  • 原文地址:https://blog.csdn.net/weixin_44453694/article/details/126182104