库文件

563 阅读3分钟

1.什么是库文件?

可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类。
库文件一般指计算机上的一类文件,分为静态库和动态库两种。

2.静态库

  • 静态库的本质就是将多个目标文件打包成一个文件
    
  • 链接静态库就是将库中被调用的代码复制到调用模块中
    
  • 静态库的拓展名是.a 例:libxxx.a
    

3.动态库

  • 链接动态库不需要将被调用的函数代码复制到包含调用代码的可执行文件中,相反链接器会在调用语句处嵌入一段指令,在该程序执行到这段指令时,会加载该动态库并寻找被调用函数的入口地址并执行之。
    
  • 如果动态库中的代码同时为多个进程所用,动态库在内存的实例仅需一份,为所有使用该库的进程所共享,因此动态库亦称共享库。
    
  • 动态库的拓展名是.so 例libxxx.so
    

4.静态库和动态库比较

  • 静态库的优缺点
    优点:
        执行速度快
        可执行程序不依赖库的存在
    缺点:
        文件体积相对较大
        更新困难,维护成本高
    
  • 动态库的优缺点
    优点:
        可执行文件文件体积小,节省空间
        易于连接,便于更新维护
    缺点:
        文件执行速度相对较慢
        可执行程序依赖库文件的存在
    

5.动态库的动态加载

  • 在程序执行的过程中,开发人员可以动态加载共享库
    
  • 在程序中动态加载共享库需要调用一组特殊的函数,它们被声明于一个专门的头文件中,并在一个独立的库中予以实现。
    
  • 使用这组函数需要包含此头文件,并链接该库
    #include <dlfcn.h>
    -ldl
    
  • void* dlopen(char const* filename, int flag);
      功能:将共享库载入内存并获得其访问句柄
      参数:filename 动态库路径,若只给文件名不带目录,则根据LD_LIBRARY_PATH环境变量的值搜索动态库
            flag 加载方式,可以取下值:
                RTLD_LAZY-延迟加载,使用动态库中的符号时才真的加载进内存
                RTLD_NOW-立即加载
      返回值:成功返回动态库的访问句柄,失败返回NULL
      句柄:句柄唯一地标识了系统内核所维护的共享库对象,将作为后续函数调用的参数
    
  • void* dlsym(void* handle,char const* symbol);
      功能:从已被加载的动态库中获取特定名称的符号地址
      参数: handle 动态库访问句柄
             symbol 符号名
      返回值:成功返回给定符号的地址,失败返回NULL
      该函数所返回的指针为void* 类型,需要造型为与实际目标类型相一致的指针,才能使用
    
  • int dlclose(void* handle);
      功能:从内存中卸载动态库
      参数: handle 动态库句柄
      返回值:成功返回0,失败返回非0
      所卸载的共享库未必会真的从内存中立即消失,因为其他程序可能还需要使用该库
      只有所使用的该库的程序都显示或隐式地卸载了该库,该库所占用的内存空间才会真正的得到释放
      无论所卸载的共享库是否真正被释放,传递给dlclose函数的句柄都会在该函数成功返回后立即失效
    
  • char* dlerror(void);
      功能:获取在加载、使用和卸载共享库过程中所发生的错误
      返回值:有错误则返回指向错误信息字符串的指针,否则返回NULL
      例如:
          void* handle = dlopen("libmath.so", RTLD_NOW);
          if(!handle){
              fprintf(stderr, "dlopen:%s\n", dlerror());
              exit(EXIT_FAILURE);
          }
    
  • 辅助工具
      查看符号表:nm
          列出目标文件、可执行程序、静态库或共享库中的符号
          例: nm libmath.a
      查看依赖:ldd
          查看可执行文件或者共享库所依赖的共享库
          例: ldd a.out