著者アバター acidlemon
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>

<span class="notice">#ifdef _WIN32</span>
<span class="warning">// Windows System needs DLL EntryPoint
#include &lt;windows.h&gt;
BOOL APIENTRY DllMain(HANDLE, DWORD, LPVOID){
    return TRUE;
}</span>
<span class="notice">#endif</span>

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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

<span class="notice">#ifdef _WIN32</span>
<span class="warning">#include &lt;windows.h&gt;</span>
<span class="notice">#else</span>
<span class="caution">#include &lt;dlfcn.h&gt;</span>
<span class="notice">#endif</span>

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

<span class="notice">#ifdef _WIN32</span>
<span class="warning">    HMODULE handle;
    handle=LoadLibrary("plugin/testmod1.dll");</span>
<span class="notice">#else</span>
<span class="caution">    void* handle;
    handle=dlopen("plugin/testmod1.so", RTLD_LAZY);</span>
<span class="notice">#endif</span>

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

<span class="notice">#ifdef _WIN32</span>
<span class="warning">    *(void**)(&amp;func1)=GetProcAddress(handle, "testcall");
    *(void**)(&amp;func2)=GetProcAddress(handle, "testcall2");</span>
<span class="notice">#else</span>
<span class="caution">    *(void**)(&amp;func1)=dlsym(handle, "testcall");
    *(void**)(&amp;func2)=dlsym(handle, "testcall2");</span>
<span class="notice">#endif</span>
    
    func1();
    int retval=func2(3);
    printf("func2 returned %d\n", retval);

<span class="notice">#ifdef _WIN32</span>
<span class="warning">    FreeLibrary(handle);</span>
<span class="notice">#else</span>
<span class="caution">    dlclose(handle);</span>
<span class="notice">#endif</span>
    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&gt;cl testmod1.cpp /LD /link /DEF:testmod1.def /OUT:"plugin/testmod1.dll"
Z:\dsotest&gt;cl testloader.cpp /link /OUT:test.exe
Z:\dsotest&gt;test.exe
this is test call.
this is test call 2, val=3
func2 returned 4

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

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

この記事をシェア

acidlemonのアバター

acidlemon

|'-') れもんです。鎌倉市在住で、鎌倉で働く普通のITエンジニアです。 30年弱住んだ北海道を離れ、鎌倉でまったりぽわぽわしています。