Linux静态动态库

Linux静态动态库

一、链接库的生成

1.1、静态库的生成

gcc -c  hello.c  			# 生成hello.o
ar -rcs libhello.a hello.o  # 生成libhello.a

1.2、动态库的生成

//单文件动态库编译生成
 /*caculate.c文件*/
#include "caculate.h"
//求两个数的和
int add(int a, int b)
{
    return (a + b);
}
//减法
int sub(int a, int b)
{
    return (a - b);
}
//除法
int div(int a, int b)
{
    return (int)(a / b);
}
//乘法
int mul(int a, int b)
{
    return (a * b);
}
gcc -shared -fPIC caculate.c -o libcac.so
// 多文件动态库的编译生成
gcc -shared -fPIC fun1.o fun2.o -o libcac.so

二、动态链接库的加载

2.1、系统自动加载

//当我们运行应用程序./a.out 一般会出现下面警告
./a.out: error while loading shared libraries: libmax.so: cannot open shared object file: No such file or directory

出错原因:a.out运行依赖与libmax.so,而系统环境变量中找不到libmax.so。

问题分析:
1、Linux是通过 /etc/ld.so.cache 文件搜寻要链接的动态库的。
2、/etc/ld.so.cache 是 ldconfig 程序读取 /etc/ld.so.conf 文件时系统生成的

(注意, /etc/ld.so.conf 中并不必包含 /lib 和 /usr/lib,ldconfig程序会自动搜索这两个目录)。

问题解决:
1、如果我们把 libmax.so 所在的路径添加到 /etc/ld.so.conf 中,再以root权限运行 ldconfig 程序,此时ldconfig的运行会更新 /etc/ld.so.cache 。

2、a.out运行时扫描 /etc/ld.so.cache,就可以找到 libmax.so。

3、但作为一个简单的测试例子,让我们改动系统的东西,似乎不太合适。还有另一种简单的方法,就是为a.out指定 LD_LIBRARY_PATH。

2.2、动态加载

linux提供dlopen、dlsym、dlerror和dlcolose函数获取动态链接库的函数。通过这个四个函数可以实现一个插件程序,方便程序的扩展和维护。


共享库被分为动态链接(Dynamic linking)和动态加载(Dynamic loading)两个步骤。

//动态链接体现在动态库的编译生成过程
gcc -fpic -shared -o libhello.so printhellow.c 
-fpic 	 : 指示了这是地址无关代码
-shared	 : 指示是一个共享库
//动态加载体现在dl库API使用,见下文。

void *dlopen(const char *filename, int flag)

dlopen()是一个强大的库函数。该函数将打开指定的动态连接库文件,并把它装入内存,加载库中的符号,并返回一个句柄给调用进程,可使用dlclose()来卸载打开的库。

//input parameter :  @ mode
RTLD_NOW   :立刻解析加载符号
RTLD_LAZY  :以后需要的时解析加载符号
RTLD_GLOBAL :允许导出符号 
RTLD_GROUP 
RTLD_WORLD 
RTLD_LOCAL 

//return  value
打开错误返回NULL 
成功,返回库引用句柄

void *dlsym(void *handle, const char *symbol)

函数功能:根据symbol(函数的名称),获取动态链接库中真实的函数地址,返回值是void*,指向函数的地址,供调用使用。

//示例:mytest函数的实体,编译成了so动态库
void (*pMytest)()
pMytest = (void (*)())dlsym(pHandle, "mytest");

char *dlerror(void)

当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

//示例程序
#include <dlfcn.h>  
int main(int argc, char **argv) 
{  
    void *handle;  
    double (*cosine)(double);  
    char *error;  
  
    handle = dlopen ("libm.so", RTLD_LAZY);  
    if (!handle) {  
        fprintf (stderr, "%s ", dlerror());  
        exit(1);  
    }  
  
    cosine = dlsym(handle, "cos");  
    if ((error = dlerror()) != NULL)  {  
        fprintf (stderr, "%s ", error);  
        exit(1);  
    }  
  
    printf ("%f ", (*cosine)(2.0));  
    dlclose(handle);  
    return 0;  
} 

int dlclose(void *handle)

1 、 dlclose用于关闭指定句柄的动态链接库,并将动态连接库从库中移除。
2、 注意:只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

2.3、系统加载与手动加载的区别

A、系统加载
1、应用程序只要已启动,动态库便加载到内存中去了,符号的解析查找,以及相关符号对应的函数调用,都是操作系统,帮我们完成。当应用程序进程结束后,可能动态库才会从内存中移除。

2、应用程序的编译依赖与动态库: gcc -o main mian.c -lmax

B、手动加载
1、随应用程序的需求需要时加载,不需要时直接在程序中通过DL的API函数卸载相关的动态库,节省内存。、

2、应用程序的编译依赖与动态库: gcc -o main mian.c ,应用程序main.c中手动加载

附录、参考文档

https://www.cnblogs.com/jiqingwu/p/linux_dynamic_lib_create.html

补录、库的软链接

关与库的链接:是连接动态还是静态的说明

https://blog.csdn.net/abcdu1/article/details/86083295
问题:

问题1:-l(L的小写)链接的到底是动态库还是静态库

答案:如果链接路径下同时有 .so 和 .a 那优先链接 .so

问题2:如果路径下同时有静态库和动态库如何链接静态库

答案:使用显示链接, gcc -l:lib***.a (将静态库的名字显示写出来)

或者在 gcc 编译的时候 加入参数 -static -lXXX, 则可以添加路径下面的静态库。

验证方法:

可以通过 ldd 命令查看生成的 目标文件链接的库,使用方法: ldd ***.o

****一般情况下,连接静态库时不要使用-static 选项去链接
https://www.cnblogs.com/lidabo/p/10245784.html

https://blog.csdn.net/newchenxf/article/details/51743181

原文地址:https://www.cnblogs.com/retry/p/9983353.html