1、如何整出自己的动态库:
我们可以看到 /lib /usr/lib 文件夹里面有很多.so后缀的文件,so其实是shared object file的缩写,这些都是动态链接库啦,什么是动态链接库和静态库函数库呢,静态函数库就是指:当应用程序道目标代码与函数库进行链接时,函数库中被引用的代码将被复制到最终生成的可执行文件中。而动态链接库,链接二字,顾名思义,使用它时不是真正的使用它本身而是动态的使用它的链接(文件路径,文件名,函数名)
如何编译动态库:关键参数 -fPIC , gcc -fPIC -c xxx.c
如何链接成动态库:关键参数 -shared , gcc -shared -o libxxx.so xxx.o
如何鉴别动态库:可以使用file命令 ,动态库会输出类似信息 "ELF 32-bit LSB shared object"
好,我们来创建一个吧 。
- root@zxc-Lenovo:/home/zxc/work# cat hello.c
- #include "stdio.h"
- void hello()
- {
- printf("hello world!\n");
- }
- root@zxc-Lenovo:/home/zxc/work#
root@zxc-Lenovo:/home/zxc/work# gcc -fPIC -c hello.c
root@zxc-Lenovo:/home/zxc/work# gcc -shared -o libhello.so hello.o
root@zxc-Lenovo:/home/zxc/work# file libhello.so
libhello.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped
2、整出了自己的动态库,如何使用它:
首先,编译链接自己的程序时,需要引用到我们的动态库,gcc 提供了-L参数和-l参数来分别代表动态库的路径以及文件名。
- #include "stdio.h"
- void main()
- {
- hello();
- }
gcc test.c -lhello -L. -o test
编译之后运行./test 发现竟然报错! error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory ,咦,怎么回事?原来虽然链接时链接器(dynamic linker)找到了动态库libhello.so,但动态加载器(dynamic loader, 一般是/lib/ld-Linux.so.2)却没找到。
别急,有两种办法,1、直接把libhello.so放入 /lib /usr/lib 2、把当前路径加入
环境变量LD_LIBRARY_PATH中
我们使用第二种方法实验一下
root@zxc-Lenovo:/home/zxc/work# export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
root@zxc-Lenovo:/home/zxc/work# ./test
hello world!
果然成功啦。
3、好像使用动态库还挺麻烦的,有没有一种通用的办法呢? 答案是有的!使用dl系列函数 dlopen dlsym dlclose 等
dlopen用于打开一个动态库,可以在函数中直接指定动态库的路径名,dlsym函数用于将动态库的函数映射到本地函数指针,经过映射后,就可以在本地应用程序中调用动态库中的函数完成相应的功能啦。我们来实验一下:
新建一个hello2的动态库
- root@zxc-Lenovo:/home/zxc/work# cat hello2.c
- #include "stdio.h"
- void hello()
- {
- printf("hello world!\n");
- }
- root@zxc-Lenovo:/home/zxc/work#
根据ld函数规则,创建下面的test.c
- root@zxc-Lenovo:/home/zxc/work# cat test.c
- #include "stdio.h"
- #include "dlfcn.h"
- void main()
- {
- void *handle;
- void (*fuc)(void);
-
- handle=dlopen("/home/zxc/work/libhello2.so",RTLD_NOW);
-
- fuc = dlsym(handle,"hello");
- fuc();
- dlclose(handle);
-
-
- }
编译时注意-ldl选项:gcc test.c -ldl -o test2 ,这里看到我们并没有指定动态库的路径和名称,看起来跟hello2的动态库没有任何关系,实际上动态库的调用完全是在代码中实现。
编译完成后运行仍然得到正确的结果,
root@zxc-Lenovo:/home/zxc/work# ./test2
hello world!
4、两种调用动态库的方式,你会选择哪一种呢??
阅读(1173) | 评论(0) | 转发(1) |