注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

太阳神上的博客

青青子衿,悠悠我心,但为君故,沉吟至今。

 
 
 

日志

 
 
 
 

在Linux和Window動態加載技術(so&dll)  

2007-09-29 11:57:57|  分类: 学习 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

  本來我想在Tenshi語言裡定義一些內置類(Builtin Class),在內置類裡用FLTK實現圖形界面,用Audiere來實現聲音,其它的文件I/O則用標準庫來實現,在逐步實現Tenshi的過程中,我漸漸有了一些更好,更方面,更先進的設計。其中就需要有動態加載函數的技術,這就是本篇博客的主要內容。
  程序的運行庫有兩種,一種是靜態庫,這種庫在編譯時就已連接到可執行文件裡,另外一種便是動態庫,在程序運行時再加載,確切地說,動態庫也分為兩種,一種是加載可執行程序時加載動態庫,另外就是在程序運行時再加載,本文就是講的後一種,這種方法動態性是最高的。
  在Linux和Windows裡,為這種機制提供了相應的庫。使用方法幾乎完全一致,只有函數名不同而已。使用時分為三步:
1 通過動態庫名獲取相應的句柄。
2 從夠本中按名獲取相應的函數地址。
3 關閉動態庫。
  下面以Linux為例,獲取C函數的指針。先創建相應的動態庫:
greet.c:

#include <stdio.h>

void greet(){
    printf("Hello,world\n");
}

用gcc的-fpic來生成位置無關代碼(Position Independant Code)

gcc -c -fpic greet.c

這樣就有了一個greet.o的目標代碼,再用-shared選項來編譯生成動態庫greet.so

gcc -shared -o greet.so greet.o

main.c如下:

#include <stdio.h>
#include <dlfcn.h>

typedef void (*func_type)();

int main(){
    //open library
    void *greet_module=dlopen("./greet.so",RTLD_LAZY);
    if(greet_module==NULL){
        fprintf(stderr,"Open library failed!\n");
        return -1;
    }
   
    //get symbol
    func_type greet_func=(func_type)dlsym(greet_module,"greet");
    if(greet_func==NULL){
        fprintf(stderr,"Get symbol failed!\n");
        return -1;
    }
   
    //use symbol
    greet_func();
       
    //close library
    dlclose(greet_module);   
    return 0;
}

  編譯main.c時要注意要加上鏈接選項-ldl。在dlopen裡使用了庫的相對路徑,這樣就可以保證用當前目錄下的greet.so文件,一般而言,dlopen的尋徑順序在POSIX如下:

  1. dlopen中用相對或絕對路徑指明的動態庫文件;
  2. 在環境變量LD_LIBRARY_PATH裡的同名動態庫;
  3. /etc/ld.so.cache中動態庫列表;
  4. /lib和/usr/lib

由於在默認情況下,當前目錄一般不在2,3,4三種情況下,所以在Linux實現時,如果要保證能順利運行,這裡我使用了"./greet.so"而不是"greet.so"。不過在Windows裡就不必了。
  那如何獲取C++的成員函數呢,可以使用上次定義過的GetMemberAddress函數來獲取:

GetMemberAddress函數有一些特殊,它的聲明與實現並不相同(有意的)
聲明時:
void *GetMemberAddress(...);

實現時:
void *GetMemberAddress(void *addr){
   return addr;
}

使用時:
func_type foo=(func_type)GetMemberAddress(&Classname::methodName)

  其實可以使用虛函數來實現C++的動態綁定,比上面的方法比較猥瑣。
  那如何獲取動態庫中的對象呢,可以在動態庫中定義返回這些對象的引用的函數來解決。
  以上全是在Linux中的實現,如果在Windows裡,相應的函數和數據類型稍有變化,如上main.c為:

 #include <stdio.h>
#include <windows.h>

typedef void (*func_type)();

int main(){
    //Load library
    HINSTANCE greet_module=LoadLibrary("greet.dll");
    if(greet_module==NULL){
        fprintf(stderr,"Load library failed!\n");
        return -1;
    }
   
    //get procedure address
    func_type greet_func=(func_type)GetProcAddress(greet_module,"greet");
    if(greet_func==NULL){
        fprintf(stderr,"Get procedure address failed!\n");
        return -1;
    }
   
    //use the procedure
    greet_func();
   
    //free library
    FreeLibrary(greet_module);
    return 0;
}


  评论这张
 
阅读(557)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017