Linux上で共有ライブラリないのクラスを動的ロードしようと調べてみたが、時間が経つと忘れてしまいそうなので、記録しておく。
まずは、基本的なおさらいとして、Linux上で共有ライブラリ内の関数を動的ロードする手順を書いておく。
- dlopenでライブラリを開き、ハンドルを取得する。
- dlsymでシンボルのアドレスを取得する。
- 2.で取得したものを利用する。
- dlcloseでハンドルを閉じる。
続いて共有ライブラリ内のクラスを動的にロードする方法を記載する。サンプルとして使用する共有ライブラリは以下のソースの様になっている。
- libtest.hpp
#ifndef __LIBTEST_HPP__ #define __LIBTEST_HPP__ #include <iostream> #include <string> #include <cstdlib> using namespace std; namespace otter { class Message { private: string message; protected: public: static char* DEFAULT_MESSAGE; Message(); Message(string message); ~Message(); bool say(); }; typedef Message* CreateMessageDefault(); typedef Message* CreateMessage(string); typedef void DestroyMessage(Message*); } #endif //__LIBTEST_HPP__
- libtest.cpp
#include <libtest.hpp> using namespace std; char* otter::Message::DEFAULT_MESSAGE="Hello World!"; extern "C" otter::Message* createDefaultObject() { return new otter::Message; } extern "C" otter::Message* createObject(string message) { return new otter::Message(message); } extern "C" void destroyObject(otter::Message* object) { delete object; } otter::Message::Message() { this->message = otter::Message::DEFAULT_MESSAGE; } otter::Message::Message(string message) { this->message = message; } otter::Message::~Message() { } bool otter::Message::say() { cout << this->message << endl; return EXIT_SUCCESS; }
クラスの内容としては単純で、インスタンス生成時に引数に指定した文字列もしくは引数が内場合はデフォルトの文字列をメンバ関数say()を使って出力するというものになっている。
ソースファイルないにはオブジェクト生成用の関数を定義している。dlsymでクラス自体をシンボルとして取得できないようなので、オブジェクトを生成する関数のシンボルを取得する必要があるようだ。また、シンボル取得時に関数ポインタを扱うため、型名が長くてよく分からなくなる。そのため、ヘッダーファイル内にtypedefを記載している。
これを共有ライブラリとしてビルドして、利用可能な状態にしておく。そこら辺の処理は話の本筋から外れてしまうためここでは記載しない。
続いて共有クラスを利用する方法を記載する。以下のようにmain関数を作成する。
- main.cpp
#include <libtest.hpp> #include <dlfcn.h> using namespace std; using namespace otter; int main(int argc, char* argv[], char* envp[]) { void* handle = dlopen("/home/inchoki/dev/lib/libtest.so", RTLD_LAZY); CreateMessageDefault* createDefault = (CreateMessageDefault*)dlsym(handle, "createDefaultObject"); CreateMessage* create = (CreateMessage*)dlsym(handle, "createObject"); DestroyMessage* destroy = (DestroyMessage*)dlsym(handle, "destroyObject"); otter::Message* p_msg = (otter::Message*)create("Hello from Dynamic Load Lib!"); p_msg->say(); destroy(p_msg); otter::Message* p_dmsg = (otter::Message*)createDefault(); p_dmsg->say(); destroy(p_dmsg); dlclose(handle); return EXIT_SUCCESS; }
基本的に共有ライブラリから関数を呼び出す流れと同じようになる。dlsymを利用してオブジェクトせいせい関数を準備し、後はその関数からオブジェクトのポインタを取得して利用するという流れになる。
当然dl*関数を利用するのでdlfcn.hが必要になり、ビルド時にはlibdlをリンクする必要がある。
試してはみたものの、プラグインの仕組みなんかが必要にならない限り、ビルド時にリンクすれば十分な気もする。
内容については次のサイトを参考にした。
コメント