最近在学习如何使用Android下的源码重写Java层的API,其中在使用JNI的时候就要用到Android系统/system/lib目录下的链接库,于是又重新学习了一番如何在Linux下引用.so文件,与在Android下有少许不同。闲话不多说,进入主题。
First,新建了一个文件setSo.c,代码如下:
First,新建了一个文件setSo.c,代码如下:
#include<stdio.h> char *get_string(char *cmd) { char *one = "i am the best"; char *too = "i am the best too"; char *re = "read"; if(*re == *cmd) { return one; } else return too; }
这是一段非常简单的代码,就是返回一个字符串。编译:gcc setSo.c -shared -o setSo.so 生成了名为setSo.so的链接库,是被引用的部分。 Second,新建文件getso.c,代码如下#include<stdio.h> #include<stdlib.h> #include <string.h> #include <unistd.h> //#include <dlfcn.h> #include <dlfcn.h> int main() { void* filehandle0 = dlopen("/root/workspace/TestSo/produceSo/setSo.so", RTLD_LAZY|RTLD_GLOBAL ); char *ll; if(filehandle0) { printf("open so success!\n"); char*(*requesttostring)(char*); char *cmd = "read"; requesttostring = (char *(*)(char*))dlsym(filehandle0, "get_string"); if( requesttostring ) { printf("call function requesttostring OK!\n"); ll = requesttostring(cmd); printf("the value of requesttostring is %s\n", ll); } else { printf("call function getinformation! ERROR!\n"); } printf("ok\n"); } return 0; }
这里需要重点解释的是 dlopen() 和 dlsym() 两个函数(包含在<dlfcn.h>文件中)。dlopen()的原型为: void *dlopen(const char * pathname, int mode),pathname为要引用的链接库的路径,mode为常量,分为两种:RTLD_LAZY 暂缓决定,等有需要时再解出符号;RTLD_NOW 立即决定,返回前解除所有未决定的符号。RTLD_LOCAL 与RTLD_GLOBAL作用相反,动态库中定义的符号不能被其后打开的其它库重定位。如果没有指明是RTLD_GLOBAL还是RTLD_LOCAL,则缺省为RTLD_LOCAL。RTLD_GLOBAL 动态库中定义的符号可被其后打开的其它库重定位。RTLD_GROUPRTLD_WORLD中间用“|”连接。dlsym()的原型为void* dlsym(void* handle,const char* symbol),handle为dlopen()的返回值,symbol为要引用的库中的函数的名字。在本例中,symbol即为要引用的库setSo.so中的函数get_string。使用dlsym要特别注意指针问题,具体请参详本例。Third,编写完getso.c后,要对此文件进行编译:gcc -o getso getso.c -ldl 请不要忘记后面的-ldl ,如果不加的话可能会报错:undefined reference to `dlsym'。测试:./getso结果:open so success!call function requesttostring OK!the value of requesttostring is i am the bestok至此,引用完毕.小弟第一次写文章,不当之处欢迎指教,谢谢!