acidlemon
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 <windows.h> 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 <stdio.h> #include <stdlib.h> <span class="notice">#ifdef _WIN32</span> <span class="warning">#include <windows.h></span> <span class="notice">#else</span> <span class="caution">#include <dlfcn.h></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**)(&func1)=GetProcAddress(handle, "testcall"); *(void**)(&func2)=GetProcAddress(handle, "testcall2");</span> <span class="notice">#else</span> <span class="caution"> *(void**)(&func1)=dlsym(handle, "testcall"); *(void**)(&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
[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をそこに押し込めば、プラットフォームを意識しないダイナミックロードができるようになりそうですねーみたいな話。
いや何の役に立つのかは知りませんが。