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