动态 库(Dynamic Link Library)(Linux下称共享对象技术Share Object)的使用,其目的是减小程序大小,节省磁盘空间。Linux下的动态库文件命名通常为<name>.so,或 <name>.so.<ver>。 下面主要对动态库的制作及使用作一个简单介绍。
1, 动 态库函数的制作.
1.1 动态库中的函数定义跟普通函数没什么区别. 如下:
//func.c
void print(char *buf)
{
printf(“Hello World: %s/n”,buf);
}
1.2 动态库的编译.
有两种编译方式:
(a) gcc -shared -fpic -o libfunc.so func.c
(b) gcc -c -fpic -o func.o func.c
gcc -shared -o libfunc.so func.o
值得说明的是: 这里的-fpic 表示将 目标编译成可重入的格式, pic 是position indepent code 的简称. 如果不加上这个选项, 在执行使用这个动态库的时候, 会出现类似如下的错误:
error while loading shared libraries:/apps/src/demo/libfunc.so cannot restore segment prot after reloc: Permission denied
-shared 表 示链接成动态库. 动态库目标文件的命名跟静态库一样, 只是将扩展名该为so 即可, 如: libNAME.so
2, 动态库的使用.
使用动态库中的函数有两种调用方式:静态调用和动态调用。
2.1 静态调用,也称为隐式调用,由编译器在编译时完成对动态库加载和程序结束时动态库卸载的编码。 请看如下代码:
//test.c
void print(); // 函数声明, 在动 态库libfunc.so 中定义.
int main(void)
{
print();
return 0;
}
2.2 动态调用,使用dl系列函数,完成对动态库函数的调用。
2.2.1 重要的dlfcn.h头文件
LINUX下使用动态链接库,源程序需要包含dlfcn.h头文件,此文件定义了调用动态链接库的函数的原型。
2.2.2 dlerror
原型为: const char *dlerror(void);
当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。
2.2.3 dlopen
原型为: void *dlopen (const char *filename, int flag);
dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。
filename: 如果名字不以/开头,则非绝对路径名,将按下列先后顺序查找该文件。
(1) 用户环境变量中的LD_LIBRARY_PATH值;
(2) 动态链接缓冲文件/etc/ld.so.cache
(3) 目录/lib,/usr/lib
flag表示在什么时 候解决未定义的符号(调用)。取值有两个:
1) RTLD_LAZY : 表明在动态链接库的函数代码执行时解决。
2) RTLD_NOW : 表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。
dlopen调用失败时,将返回NULL值,否则返回的是操作句柄。
2.2.4 dlsym : 取函数执行地址
原型为: void *dlsym(void *handle, char *symbol);
dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。
如 程序代码: void (*print_func)(char *buf); /* 说明一下要调用的动态函数print_func*/
print_func=dlsym("libfunc.so","print"); /* 打开libfunc.so共享库,取print函数地址 */
print_func("John"); /* 调用print_func函数 */
2.2.5 dlclose : 关闭动态链接库
原型为: int dlclose (void *handle);
dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
2.3编译:
gcc -L/apps/src/demo/ test.c -lfunc -o test
上面这条编译链接指令, 我们都非常熟悉了. 接 下来就可以执行test 文件了.
很不幸, 当 我们敲下:
./test
时, 问 题又出来了:
./test: error while loading shared libraries: libfunc.so: cannot open shared object file: No such file or directory
很明显, 是 动态库的路径不正确, 编译时用-L 指定的库文件路径, 在执行文件时不起作用了. 怎样让可执行文件找到我们自己建立的库呢? 这 里有几种方法:
( a ) 将库文件libfunc.so 拷贝 到/usr/lib 或 /lib 或 /usr/local/lib 下, 默认情况下, 系统从这几 个地方寻找库文件.
( b ) 导出 符号LD_LIBRARY_PATH, 如export LD_LIBRARY_PATH=/apps/src/demo/
如果有多条路径, 用 ‘:’ 分割.
( c ) 将库文件的路径添加到 /etc/ld.so.conf 中去, 并执行/sbin/ldconfig
( d ) 在编译链接时添加选项目 -Wl,--rpath 指 定, 如:
gcc -Wl,--rpath,/apps/src/demo/ -L/apps/src/demo/ test.c -lfunc -o test
或者
gcc -Wl,--rpath -Wl,/apps/src/demo/ -L/apps/src/demo/ test.c -lfunc -o test
补充:查看文件使用的动态 库用ldd命令.
参考文献:
GCC: the complete reference