2006/06/02

WindowsやらLinuxやらでダイナミックロード

Windowsでダイナミックロードしたいときは何を使うー? そうです、DLL(Dynamic Link Library)です。

Linuxとか(POSIX系全般)でダイナミックロードしたいときは何を使うー? そうです、SOモジュール(Dynamic Shared Object)です。

そのぐらいの知識はあったし、DLLやSOモジュールを実行時リンクで読み込んだことやWindowsでDLLをLoadLibraryしたことはあったけどLinuxとかでSOモジュールを動的に読み込んだことがなかった。ので、やってみた。今日はそのメモ。

testmod1.cpp

DLLになったりSOモジュールになったりするほうのcppファイル。

#include <stdio.h>

#ifdef _WIN32
// Windows System needs DLL EntryPoint
#include <windows.h>
BOOL APIENTRY DllMain(HANDLE, DWORD, LPVOID){
    return TRUE;
}
#endif

extern "C"{

void testcall(){
    printf("this is test call.\n");
}

int testcall2(int val){
    printf("this is test call 2, val=%d\n", val);
    return val+1;
}

}
testloader.cpp

DLLなりSOモジュールなりを動的にロードするほうのcppファイル。システムの違いを明確にするために、#ifdefで分けまくりです。

#include <stdio.h>
#include <stdlib.h>

#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif

int main(int argc, char* argv[]){
    void (*func1)(void);
    int (*func2)(int);

#ifdef _WIN32
    HMODULE handle;
    handle=LoadLibrary("plugin/testmod1.dll");
#else
    void* handle;
    handle=dlopen("plugin/testmod1.so", RTLD_LAZY);
#endif

    if(!handle){
        printf("cant open testmod1.so\n");
        exit(1);
    }

#ifdef _WIN32
    *(void**)(&func1)=GetProcAddress(handle, "testcall");
    *(void**)(&func2)=GetProcAddress(handle, "testcall2");
#else
    *(void**)(&func1)=dlsym(handle, "testcall");
    *(void**)(&func2)=dlsym(handle, "testcall2");
#endif
    
    func1();
    int retval=func2(3);
    printf("func2 returned %d\n", retval);

#ifdef _WIN32
    FreeLibrary(handle);
#else
    dlclose(handle);
#endif
    return 0;

}
testmod1.def

あと、WindowsでDLLつくるときはモジュール定義ファイルか__declspec(dllexport)が必要なので、今回は前者でエクスポートテーブルを定義。

LIBRARY testmod1
EXPORTS
    testcall    @1
    testcall2    @2

こいつをLinuxでコンパイルして実行するとー

[kawazoel@sekiya dsotest]$ g++ testmod1.cpp -g -shared -o plugin/testmod1.so
[kawazoel@sekiya dsotest]$ g++ testloader.cpp  -g -rdynamic -ldl -o test
[kawazoel@sekiya dsotest]$ ./test 
this is test call.
this is test call 2, val=3
func2 returned 4

Windows(Visual Studio 2005)でコンパイルして実行するとー

Z:\dsotest>cl testmod1.cpp /LD /link /DEF:testmod1.def /OUT:"plugin/testmod1.dll"
Z:\dsotest>cl testloader.cpp /link /OUT:test.exe
Z:\dsotest>test.exe
this is test call.
this is test call 2, val=3
func2 returned 4

とまぁこんな感じでどちらのプラットフォームでも同じようにダイナミックロードすることができましたー。あとはなんかこれをカプセル化するようなクラスをつくって、#ifdefをそこに押し込めば、プラットフォームを意識しないダイナミックロードができるようになりそうですねーみたいな話。

いや何の役に立つのかは知りませんが。

うされもん @acidlemonについて

|'-')/ acidlemonです。鎌倉市在住で、鎌倉で働く普通のITエンジニアです。

30年弱住んだ北海道を離れ、鎌倉でまったりぽわぽわしています。

外部サイト情報

  • twitter
  • github
  • facebook
  • instagram
  • work on kayac