Chinaunix首页 | 论坛 | 博客
  • 博客访问: 70041
  • 博文数量: 26
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 310
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-02 16:13
文章分类

全部博文(26)

文章存档

2009年(18)

2008年(8)

我的朋友
最近访客

分类: C/C++

2008-08-25 12:59:06

A mechanism by which a computer program can, at runtime, load library(or other binary) into memory(attach a shared library to the address space of the process during execution), retrieve the address of functions and variables contained in the library, execute those functions or access those variables, and unload the library from memory.
和Dynamic link是不同的。
   dynamic link编译时要-l -L等。而dyn load编译时根本不用-l -L。
   程序启动的时候,这个库甚至可以根本不存在,只要在加载前存在就可以了。而dyn link在启动时必须存在。
Dynamic loading常用来实现插件,可以在线(运行时)动态升级库文件。


例子:在外部库有一个函数fun();在运行时根据你任意输入的库文件(当然要存在才行)动态装载这个库中的fun()函数执行,然后卸载这个库。查看输出验证。
 

// dyn1.cpp

#include <iostream>
using namespace std;

// 这个ifdef是必须的, 如果是C++编译器有name mangle, 而在主函数中是通过fun来找函数的, extern后不会改变函数名

#ifdef __cplusplus
extern "C"
#endif
void fun(const char* str)
{
    cout<<"这是第 一 个函数 : "<<str<<endl;
}

// dyn2.cpp

#include <iostream>
using namespace std;

// 这个ifdef是必须的, 如果是C++编译器有name mangle, 而在主函数中是通过fun来找函数的, extern后不会改变函数名

#ifdef __cplusplus
extern "C"
#endif
void fun(const char* str)
{
    cout<<"这是第 二 个函数 : "<<str<<endl;
}

// main.cpp

// 运行时输入库文件名称,显示这个库文件中的fun()函数的输出, 知道输入不是库文件名退出

#include <dlfcn.h>
#include <iostream>
#include <string>
using namespace std;

typedef void (*PFUN)(const char*); // 函数指针类型定义


int display(const char* libver);

int main()
{
    while(true)
    {
        cout<<"输入库文件名称:";
        string str;
        cin>>str;
    
        int ret = display(str.c_str());
        if(ret == -1)
        {
            return -1; // 输入不是库文件的串, 程序退出

        }
        cout<<"-------------------------------"<<endl;
    }
    return 0;
}

int display(const char* libver)
{
    void *handle = dlopen(libver, RTLD_LAZY);
    if(handle == NULL)
    {
        cout<<"dlopen error : "<<dlerror()<<endl;
        return -1;
    }

    PFUN pfun = (PFUN)dlsym(handle, "fun");
    if(pfun == NULL)
    {
        cout<<"dlsym error : "<<dlerror()<<endl;
        return -1;
    }

    (*pfun)("测试动态装载"); // 调用库文件中的fun(),不同库中的显示会不同, 这就是动态装载, 可以实现在线版本更新


    int ret = dlclose(handle);
    if(ret != 0)
    {
        cout<<"dlclose error : "<<dlerror()<<endl;
        return -1;
    }
    return 0;
}

# makefile文件
all:main libdynload.so.1 libdynload.so.2
 
main:main.o
 CC main.o -ldl -o $@
 
libdynload.so.1:dyn1.o
 CC -G -o $@ $^
 
libdynload.so.2:dyn2.o
 CC -G -o $@ $^
 
.SUFFIXES : .o  .cpp
 
.cpp.o:
 CC -KPIC -c $*.cpp -o $*.o
 
.PHONY:clear
clear:
 rm main.o dyn1.o dyn2.o libdynload.so.1 libdynload.so.2

用make指令生成main程序后执行例子如下
输入库文件名称:libdynload.so.1
这是第 一 个函数 : 测试动态装载
-------------------------------
输入库文件名称:libdynload.so.2
这是第 二 个函数 : 测试动态装载
-------------------------------
输入库文件名称:libdynload.so.1
这是第 一 个函数 : 测试动态装载
-------------------------------
输入库文件名称:exit
dlopen error : ld.so.1: main: fatal: exit: open failed: No such file or directory


如果要动态装载C++类,可以在上面的fun()函数中new一个类对象。好像只有在函数中new,没有办法直接dlsym一个类对象。
在dyn load的函数中可以有任何C++的特性。但是如果这个函数的参数是string的话,比如如果把上面dyn1.cpp中的fun参数从const char* 改为string,编译能够通过,但是运行时装载这个库执行函数是core dump。不知道为什么?
 
阅读(675) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~