动态库的概念和优势在这就不多说了,这里只说编译和调用。
下面会一步步演示如何用编译使用动态库及如何解决问题。
当然如何还会具体的演示调用技巧。
1.直接用编译方式使用动态库。
动态地将程序和动态库链接,并让其在执行时加载库(如果它已在内存中则不会重复加载)
2.直接在代码中加载动态库。
程序在需要时再去加载一个特定的库(已加载则不必),然后调用该库中的某一特定函数.
/*
例子目录结构如下,具体代码附在页面最后。
[root@ol64 test4]# ls *
main.c
lib:
add.c calc.h sub.c
操作系统: Oracle Linux 6.4
编译版本:
[root@ol64 test4]# gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3)
*/
编译动态库:
直接用gcc命令行搞定:
[root@ol64 lib]# gcc -o libcalc.so -m64 -fPIC -shared add.c sub.c
[root@ol64 lib]# ldd libcalc.so
linux-vdso.so.1 => (0x00007fff811ff000)
libc.so.6 => /lib64/libc.so.6 (0x00007fc3c51e9000)
/lib64/ld-linux-x86-64.so.2 (0x0000003e66600000)
[root@ol64 lib]# size libcalc.so
text data bss dec hexfilename
1183 488 16 1687 697libcalc.so
1.直接用编译方式使用动态库:
gcc方式:
一步一步看我的演示过程:
//会说找不到头文件
[root@ol64 test4]# gcc -m64 -o demo2 main.c
main.c:3:18: error: calc.h: No such file or directory
//加上-I参数后可以找到头文件了,但会提示说找到被调用的两个函数 "sub"和"add"
[root@ol64 test4]# gcc -m64 -I./lib -o demo2 main.c
/tmp/ccWoakff.o: In function `main':
main.c:(.text+0x14): undefined reference to `sub'
main.c:(.text+0x25): undefined reference to `add'
collect2: ld returned 1 exit status
//把动态库参数加上,这次顺序编译成功了。但用ldd 查看,会发现 "libcalc.so => not found"
[root@ol64 test4]# gcc -m64 -L./lib -lcalc -I./lib -o demo2 main.c
[root@ol64 test4]# ldd demo2
linux-vdso.so.1 => (0x00007fff1612e000)
libcalc.so => not found
libc.so.6 => /lib64/libc.so.6 (0x0000003e66e00000)
/lib64/ld-linux-x86-64.so.2 (0x0000003e66600000)参数说明请看:编译小结(1) GCC多平台安装(Linux,Aix,HP-UX,Solaris)及编译参数
//不出所料,编译时会报找不到libcalc.so库文件
[root@ol64 test4]# ./demo2
./demo2: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory解决方法有好多种,
1. 在 LD_LIBRARY_PATH 中加入路径
export LD_LIBRARY_PATH=`pwd`/lib
2. /etc/ld.so.conf中用ldconfig载入
2.1 echo "/xcl/test4/lib" >> /etc/ld.so.conf
2.2 ldconfig
2.3 ldconfig -v|grep libcalc.so
3. 建个软链接到.lib或/usr/lib中
具体为什么可以查看后面附的动态库搜索路径顺序.
在编译时的解决方法:
关键在 " -Wl,-rpath" 参数。它可以同时指定多个路径,中间用","分隔
[root@ol64 test4]# gcc -m64 -L./lib -lcalc -I./lib -Wl,-rpath,lib/ -o demo3 main.c
[root@ol64 test4]# ldd demo3
linux-vdso.so.1 => (0x00007fff7a6e5000)
libcalc.so => lib/libcalc.so (0x00007f5f0f6db000)
libc.so.6 => /lib64/libc.so.6 (0x0000003e66e00000)
/lib64/ld-linux-x86-64.so.2 (0x0000003e66600000)
[root@ol64 test4]# ./demo3
add() = 8
sub() = 2
MAIL:xcl_168@
BLOG:外链网址已屏蔽 问题: 为什么加上这个参数就可以,我不是在编译中加上了"-L"参数吗?
参考:外链网址已屏蔽
"-L" 表示在编译时查找。
"-Wl,-rpath" 表示在程序运行时,优先查找的顺序。
Makefile方式:
请查看: 编译小结(5) Makefile实用小结
2.采用动态调用方式使用动态库.
代码 :
#include
#include
#include
//#include "lib/calc.h"
#include "calc.h"
int main(void)
{
//RTLD_LAZY表示暂时不去处理未定义函数,先把库装载到内存,等用到没定义的函数再说;
void *handle = dlopen("/xcl/test4/lib/libcalc.so",RTLD_LAZY);
if(!handle)
{
printf("[main] open failed! %s\n",dlerror());
return -1;
}
typedef int (*sofun_add)(int x,int y);
sofun_add cadd = (sofun_add)dlsym(handle,"add");
if(!cadd)
{
printf("[main] cadd() failed! %s\n",dlerror());
dlclose(handle);
return -2;
}
printf("[main] cadd() = %d\n",cadd(3,5));
dlclose(handle);
return 0;
}
[root@ol64 test4]# gcc -m64 -I./lib -ldl -o calldemo2 callso.c
[root@ol64 test4]# ./calldemo2
[main] cadd() = 8
如在编译时出现"undefined reference to `dlopen' "错误,说明你编译时没有加上"-ldl",即没指定dlopen所引用的库libdl.a库.
小技巧:
出现这类错误时,可能通过 man 函数名 可查到要链接的库。
如 man dlopen 时出现下面一行,告知你编译时要加上 "-ldl"
Link with -ldl.
再附一些常用的:
lc 是link libc
lm 是link libm
lz 是link libz
动态调用相关的函数说明:
在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。
dlopen函数常用模式:
RTLD_LAZY 暂缓决定,表示暂时不去处理未定义函数,
先把库装载到内存,等用到没定义的函数再说.
RTLD_NOW 立即决定,表示马上检查是否存在未定义的函数,
若存在,则dlopen以失败告终.
dlsym()的第一个参数为dlopen()返回的句柄,即符号在库中的地址。
使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。
dlclose()用于关闭指定句柄的动态链接库,不过只有当此动态链接库的使用计数为0时,
才会真正被系统卸载。
上面这些函数都归属于头文件:#include .
附录 :
动态链接,执行时搜索路径顺序:
1. 编译目标代码时指定的动态库搜索路径
2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径
3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径
4. 默认的动态库搜索路径/lib
5. 默认的动态库搜索路径/usr/lib
相关环境变量:
LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径
LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径
演示代码:
[root@ol64 lib]# cat calc.h
#ifndef __CALC_H_
#define __CALC_H_
int add(int x,int y);
int sub(int x,int y);
[root@ol64 lib]# cat add.c
#include "calc.h"
int add(int x,int y)
{
return (x + y);
}
[root@ol64 lib]# cat sub.c
#include "calc.h"
int sub(int x,int y)
{
return (x - y);
}
[root@ol64 test4]# cat main.c
#include
#include "calc.h"
int main(void)
{
printf("add() = %d \nsub() = %d\n",add(5,3),sub(5,3));
printf("MAIL:xcl_168@ \nBLOG:外链网址已屏蔽\n");
return 0;
}
MAIL: xcl_168@
BLOG:外链网址已屏蔽