Linux_静态库与动态库的制作与使用

1. 什么是库

1.1 库:

  • 本质上来说库是一种可执行的二进制代码 (但不可以独立执行), 可以被操作系统载入内存执行. 由于windows 和linux 的平台不同 (主要是编译器、汇编器和连接器的不同), 因此二者库的二进制是不兼容的. 本文仅限于介绍linux 下的库. linux 下的库有两种: 静态库和共享库 (动态库).
  • Windows下的库有两种: 静态库(.lib)和动态链接库(.dll).
  • Linux下的库有两种: 静态库(.a)和共享库(.so).

1.2 链接方式:

  • 库的链接方式分为静态链接和动态链接

    静态链接: 链接静态库生成可执行程序, 直接将库中我们用到的函数的实现代码指令, 写入到了可执行程序文件中, 程序运行的时候没有什么依赖.

    动态链接: 链接动态库生成可执行程序, 并没有把库中函数的实现指令直接拿过来写入可执行程序中, 而是在可执行程序中记录了库中函数的符号信息表, 在运行可执行程序的时候再去加载动态库到内存中, 如果动态库不存在, 则程序无法运行.
    Linux_静态库与动态库的制作与使用_第1张图片

1.3 制作库的目录及源文件:

  • 在以下文件夹中制作并存放动态库与动态库:
    文件夹main: 存放制作库的源文件, 以及测试源文件.
    文件夹share_libraries: ./lib 文件夹中存放动态库, ./include文件夹中存放头文件.
    文件夹static_libraries: ./lib 文件夹中存放动态库, ./include文件夹中存放头文件.
    Linux_静态库与动态库的制作与使用_第2张图片

  • 制作静态库与动态库的源码及头文件如下:
    add.c

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

    sub.c

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

    head.h

    #ifndef __HEAD_H__
    #define __HEAD_H__
    
    int add(int a, int b);
    int sub(int a, int b);
    
    #endif
    

    main.c

    #include 
    #include "head.h"
    
    int main(int argc, char *argv[])
    {
           
    	printf("a+b=%d\n", add(3, 1));
        printf("a-b=%d\n", sub(3, 1));
    	return 0;
    }
    

2. 静态库

2.1 什么是静态库

  • 静态库文件名的命名方式是"libxxxx.a", 库名前加"lib", Windows和Linux下都是后缀".a", "xxx"为静态库名字, Windows下的静态库名也叫libxxx.a
  • 链接时间: 静态库的代码时在编译过程中被载入程序中.
  • 链接方式: 静态库的链接时将整个函数库的所有数据都整合进了目标代码. 这样的优点时在编译后的执行程序不在需要外部的函数库支持, 因为所使用的函数都已经被编进去了. 缺点是, 如果所使用的静态库发生更新改变, 你的程序必须重新编译.

2.2 静态库的制作

  • 如果希望把源码file1.c, file2.c …fileN.c 做成库文件, 我们可以通过下命令把他们制作成静态库
    gcc -c file1.c
    gcc -c file2.c

    gcc -c flieN.c
    ar -rcs libname.a file1.o file2.o, … fileN.o
    生成的libastatic.a为静态库, 将他拷贝到’/home/gyp/mylib/static_libraries/lib’ 路径下. 将’mylib/main’ 路径下的静态库删除.
    Linux_静态库与动态库的制作与使用_第3张图片

2.3 静态库的使用

  • 在进行编译之前介绍一下与库相关的 gcc 编译选项:
    -I(大写i)   指定include包含文件的搜索路径.
    -L             指定链接所需库所在路径
    -l(小写L)  指定所需链接库的库名(比如链接libastatic.a) -lastatic
    -static:     静态链接
  • 编译与运行:
    $ gcc main.c -I …/static_libraries/include/ -L …/static_libraries/lib/ -lastatic -static
    注意: -static 禁止使用动态库, 让链接静态库后的程序彻底的独立起来, “完全静态”, 因此, 得到的二进制文件会非常大.
    Linux_静态库与动态库的制作与使用_第4张图片
  • 通过命令 du -sh a.out 与 file a.out 查看文件大小与属性:
    在这里插入图片描述

3. 动态库

3.1 什么是动态库

  • 动态库的命名方式与静态库类似, 前缀相同为"lib", Linux下后缀名为".so"即libxxxx.so, 而Windows下后缀名为".dll"即"libxxx.dll".
  • 链接时间: 动态库在编译的时候并没有被编译进目标代码, 而是当你的程序执行到相关函数时才调用该函数库里的相应函数. 这样做的缺点时因为函数库并没有整合进程序, 所以程序的运行环境必须提供相应的库. 优点时动态库的改变并不会影响你的程序, 所以动态函数库升级比较方便.
  • 编译链接: 动态库在程序编译时并不会被链接到目标代码中, 而是在程序运行时才被载入, 因为可执行文件体积较小. 有了动态库, 程序的升级会相对比较简单, 比如某个动态库升级了, 只需要更换这个动态库的文件, 而不需要去更换可执行文件. 但要注意的是, 可执行程序在运行时需要能找到动态库文件.

3.2 动态库的制作

  • 如果希望把源码file1.c, file2.c …fileN.c 做成库文件, 我们可以通过以下命令把他们制作成动态库.
    gcc -shared -fPIC -o libname.so file1.c file2.c …fileN.c
    生成的libashared.a为动态库, 将他拷贝到’/home/gyp/mylib/shared_libraries/lib’ 路径下. 将’mylib/main’ 路径下的动态库删除.
    Linux_静态库与动态库的制作与使用_第5张图片

3.3 动态库的使用

  • 编译与运行:
    $ gcc main.c -I …/share_libraries/include/ -L …/share_libraries/lib/ -lashared
    此时报错, 这个错误在下面会进行解决. 在这里插入图片描述
  • 通过命令 du -sh a.out 与 file a.out 查看文件大小与属性:
    在这里插入图片描述

3.4 程序运行报错解决方法

  • 错误: error while loading shared libraries: libashared.so: cannot open shared object file: No such file or directory
  • 这里为什么说链接器ld提示找不到库文件呢? 这是因为程序运行时没有找到动态链接库造成的. 这时一定会有人产生疑问, 我们在编译时不是使用’-L’ 指定动态库的路径了吗, 为什么运行时说我们找不到动态库呢?
  • 程序编译时链接动态库和运行时使用动态链接库的概念是不同的, 在运行时, 程序链接的动态链接库需要在系统目录下才行. 系统目录包括( /lib、/lib64、/usr/lib以LD_LIBRARY_PATH环境变量指定的路径).

  • 解决方法如下:
  1. 将需要的动态库libashread.so 拷贝到 /lib或/lib64或/usr/lib下(需要有root权限哦)
  2. 通过export修改LD_LIBRARY_PATH环境变量指定要查找库的位置
    $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:your/lib/path(绝对路径) 临时生效
    在这里插入图片描述
  3. 在编译时添加 -Wl,-rpath,/your/lib/path/ (-Wl,-R /your/lib/path/).
    在gcc中使用ld链接选项时,需要在选项前面加上前缀-Wl(小写L), -R(或-rpath)指定程序运行时库的路径.
    注意: 这个方法优点是不需要更改环境变量或者拷贝动态库到系统路径下, 它的缺点是只要更改了动态库, 那么就需要重新编译.
    Linux_静态库与动态库的制作与使用_第6张图片

你可能感兴趣的:(linux,内存数据库)