红联Linux门户
Linux帮助

linux下dlopen动态函数库的加载和dlopen函数的多平台性

发布时间:2016-06-05 10:32:14来源:linux网站作者:xuanmuzhao

一,dlopen动态函数库的加载

1.前言
如论在Linux上编程还是在windows上编程,为了程序的可扩展性,很多地方都用到了动态库的加载。这里来谈谈linux下的程序的动态函数库的创建和加载。


2.创建动态库
在Linux下边编译成so库,gcc -fPIC -shared xxx.c -o libxxx.so

int add(int a,int b)
{
return (a+b);
}

gcc -fPIC -shared caculate.c -o libcaculate.so


3.动态库调用函数介绍

void *dlopen(const char *filename,int flag);

filename:要加载动态库的绝对路径或者相对路径,相对以程序所运行的目录为准。
flag: RTLD_LAZY 暂缓决定,等到需要时,调dlsym解析符号
RTLD_NOW :立即决定,返回所有的未决函数,调用dlsym返回所有的。
以下符号可以与上面的符号一起使用。
RTLD_LOCAL:
RTLD_GLOBAL:允许导出符号,后面可以使用。
RTLD_GROUP:
RT_WORLD:

void *dlsym(void *handle,const char *symbol)

根据symbol,返回与符号对应的函数地址。
symbol可以是函数或者全局变量。
在编译的时候需要加 -ldl

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
//加载的动态库路径
#define LIB_PATH "./libcaculate.so"
//函数指针
typedef int (*CAC_FUNC)(int, int);

int main()
{
void *handle;
char *error;
CAC_FUNC cac_func = NULL;

//打开动态链接库
handle = dlopen(LIB_PATH, RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}

//清除之前存在的错误
dlerror();

//获取一个函数
*(void **) (&cac_func) = dlsym(handle, "add");
if ((error = dlerror()) != NULL)  {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("add: %d\n", (*cac_func)(2,7));

cac_func = (CAC_FUNC)dlsym(handle, "add");
printf("sub: %d\n", cac_func(9,2));

//关闭动态链接库
dlclose(handle);
exit(EXIT_SUCCESS);
}

gcc -rdynamic -o main main.c -ldl


4.常见用法
hello.c

typedef struct
{
const char *module;
int (*GetValue)(char *pszVal);
int (*PrintHello)();
}hello_api;
int GetValue(char *pstVal)
{
printf("%s\n",pstVal);
}
int PrintHello()
{
printf("%s\n","hello");
}
const hello_api hello = {
"hello",
GetValue,
PrintVal
};

再编译成lib。
这样调dlsym时,只用调用一次,就可以获取所有的函数。


caculate.c

#include <stdio.h>
typedef struct caculate_api
{
const char *module;
int (* add)(int,int);
int (* sub)(int,int);
int (* mul)(int,int);
int (* div)(int,int);
}caculate_api;

int add(int a,int b)
{
return (a + b);
}

int sub(int a, int b)
{
return (a - b);
}

int mul(int a, int b)
{
return (a * b);
}

int div(int a, int b)
{
return (a / b);
}

const caculate_api caculate = {
"caculate",
add,
sub,
mul,
div
};


main.c

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
typedef struct caculate_api
{
const char *module;
int (* add)(int,int);
int (* sub)(int,int);
int (* mul)(int,int);
int (* div)(int,int);
}caculate_api;
//动态链接库路径
#define LIB_CACULATE_PATH "./libcaculate.so"

int main()
{
void *handle;
char *error;
caculate_api *caculate;

//打开动态链接库
handle = dlopen(LIB_CACULATE_PATH, RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}

//清除之前存在的错误
dlerror();

//获取一个函数
caculate = dlsym(handle, "caculate");
if ((error = dlerror()) != NULL) 
{
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
printf("get caculate_api successfully\n");

if (caculate && caculate->module )
{
printf("module name :%s\n", caculate->module);
}

if (caculate && caculate->add )
{
printf("add: %d\n", (caculate->add)(2,7));
}

if (caculate && caculate->sub)
{
printf("sub: %d\n", (caculate->sub)(9,2));
}

if (caculate && caculate->mul)
{
printf("mul: %d\n", (caculate->mul)(3,2));
}
if (caculate && caculate->div)
{
printf("div: %d\n", (caculate->div)(8,2));
}

//关闭动态链接库
dlclose(handle);
exit(EXIT_SUCCESS);
}


二,dlopen函数的多平台性
上面已经讲解了linux下的dlopen动态库的加载。
这里谈一下这个函数实现的可移植性的程序

#define MODULE_EXT "dll"

#define dlclose(args) FreeLibrary(args)
#define dlclose_func_name "FreeLibrary"
#define dlopen(path, arg2) LoadLibrary(path)
#define dlopen_func_name "LoadLibrary"
#define dlsym(handle, func) GetProcAddress(handle, func)
#define dlsym_func_name "GetProcAddress"
#define dlerror() GetLastError()

这样就可以实现windows平台和linux平台函数的统一性。


本文永久更新地址:http://www.linuxdiyf.com/linux/21254.html