Linux高级编程——库

Linux 高级编程

库(Library)

库分为:

  • 源码库
  • 静态库:也称为静态链接库(Static Link Library)
  • 动态库:也称为共享库(Shared Library)、动态链接库(Dynamic Link Library)

通过源码库可以实现源代码级别的复用,通过静态库或共享库可以实现二进制级别的复用(保护自己的源代码)

一般情况下被调用者拥有的是:头文件、库文件、帮助手册。

制作静态库文件的步骤:

  1. 将相关源文件(.c)编译为对应的目标文件(.o),使用 gcc -c 源文件名称(xxx.c) 命令
  2. 将上一步得到的所有目标文件打包为静态库,使用 ar -cr 静态库的名(libxxx.a) 目标文件(a.o) 命令

使用静态库的命令

  • 多个库
gcc 调用者源文件 -l静态库名(不写lib和后缀.a) -L路径(.为当前路径) -o 可执行文件名
  • 单个库,无需打包,同一路径下
gcc 调用者源文件 被调用者目标文件(.o) -o 可执行文件

静态库其实就是若干个目标文件的归档文件。

制作动态库的命令

gcc -shared -fPIC 源文件名(***.c) -o 动态库文件名(lib***.so)

使用动态库的命令

  • 当前路径下:
gcc main.c -L. -l动态库名(不带.so) -o 可执行文件名
  • 配置完后(配置方法在后续)
gcc main.c -l动态库名(不带.so) -o 可执行文件名
  • 直接使用或指定(当前)路径
gcc main.c 动态库名.so -o 可执行文件名

gcc main.c ./动态库名.so -o 可执行文件名

在 Linux 系统上,静态库文件的后缀名为 .a,动态库文件的后缀名为 .so。

在Windows系统上,静态库文件的后缀名为 .lib,动态库文件的后缀名为 .dll

在编译时通常是通过 -L 和 -l 参数指定需要链接的具体库文件,前者指定库文件的搜索路径,后者指定库文件名称(不算前缀 lib) 。如果同时存在同名的静态库和动态库,则优先链接动态库。

在启动程序时,加载器(将动态库文件加载到内存中,加一次就可)会解析可执行程序,获得该程序依赖的所有动态库信息,然后在磁盘上找到它们,并将它们加载到内存中(如果之前没有加载过),如果加载器无法找到目标动态库文件或加载失败,那么程序就启动失败了,无法执行。

通过 ldd命令可以查看可执行文件依赖的动态库文件以及路径。

报错:

./main:error while loading shared libraries:lib动态库名.so:connot open shared file:No such file or directory

让链接器和加载器找到某个动态库文件的三种方法:

  • 将动态库文件拷贝到 /lib、/user/lib这两个文件夹下;

  • 设置 LD_LIBRARY_PATH 这个环境变量的值为库文件路径;(只对当前终端有效)

    export LD_LIBRARY_PATH=.
    
  • 修改 /etc/ld.so.conf 这个配置文件,将库文件的绝对路径写入其中,然后执行ldconfig 命令(刷新),让配置生效。

静态链接库和动态链接库的区别:

  1. 静态库在链接时的相关代码会被链接器提取出来,嵌入到在可执行文件中(即静态链接),成为可执行文件的一部分,所以生成的程序可以不依赖静态库独立运行,但生成的程序的体积较大。如果系统中有多个程序需要调用库文件中的函数,那么每个程序都包含一份静态库的代码,白白浪费了大量的存储空间。在程序需要更新升级时,只能重新编译生成新的可执行程序替换掉旧版程序,即全量更新,这对于大型软件来说是非常致命的。
  2. 动态库在链接时,链接器只是将其描述信息(动态库名、内部的函数名或全局变量名称等)提取出来嵌入到可执行文件中,所以生成的程序体积很小,但在运行时必须加载动态库到内存中(即动态链接),否则程序会启动失败,也就是说程序无法独立运行。如果系统中有多个程序都需要调用库文件中的函数,动态库只会被加载一次,也就是说内存中永远只有一份动态库的代码,所有程序共享一份。另外,在程序需要更新升级时更加方便,可以实现局部更新 (对外函数接口保存不变,用新版动态库直接替换旧版即可,无需重新编译可执行程序。)

动态库的两种使用方式:

  • 隐式调用:系统在程序启动时自动加载依赖的所有动态库,一旦某一个动态库加载失败,程序就无法启动,并且我们对此无法处理。这种方式使用起来更简单,甚至感觉不到动态库的存在,所以用的更多。
  • 显示调用:自己通过代码控制动态库的加载和卸载,根据需求调用其中的函数。这种方式使用起来比较繁琐,但灵活性很高,在必要时可以使用。

显示调用例子:

#include <dlfcn.h> //包含的头文件
void (*SortFun)(void *base,size_t nmemb,size_t size, int (*comper)(const void*,const void*));
int main(){
	void* lib = dlopen("./libdjsort.so.1.0.1",RTLD_NOW);//打开库
	if(NULL == lib){
        //自定义处理
        printf("error\n");
        return 0;
    }

	SortFun f dlsym(lib, "quick_sort");找库中的函数,需要指定函数名,有返回函数的首地址,没有返回NULLif(f != NULL)
	{
    	int nums[] = {5, 3, 4, 1, 2};
    	f(nums, 5, sizeof(int), cmp);
    
    	for(int i=0;i < 5; i++)
        {
            printf("%d",num[i]);
        }
	}
dlclose(lib);//关闭
}
gcc main.c -ldl //编译时需要带上dl库

关于dlopen函数的使用方法:https://blog.csdn.net/woyebuzhidao888/article/details/46634591

版本号通常的形式为:x.y.z,x 称为主版本号,y 称为次版本号, z 称为修订号或补丁号。

通常版本需要更新,可执行文件的库名称没有改,比如liba.so.1.0.0(老),liba.so.1.0.1(新)

使用软链接的方式:创建软链接名为:liba.so.1.0.1指向liba.so.1.0.0

ln -s liba.so.1.0.1 liba.so.1.0.0 

帮助手册的编写(以qsort函数为例)

### 帮助手册
<函数名>qsort

## 函数原型
<头文件>#include "qsort.h"
<函数声明>void qsort(void *base, size_t nmemb, 
            size_t size, int (*compar)(const void *, const void *));

## 参数描述
base:***
nmemb:***
...

## 返回值
函数成功返回0,失败返回1

## 示例
***
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值