問題の一般的な解決策は、関数ポインタのテーブルを宣言し、それを見つけるために単一のdlsym()を実行し、そのテーブルへのポインタを通して他のすべての関数を呼び出すことです。例(未テスト):
// libfoo.h
struct APIs {
void (*api1)(void);
void *(*api2)(int);
long (*api3)(int, void *);
};
// libfoo.cc
void fn1(void) { ... }
void *fn2(int) { ... }
long fn3(int, void *) { ... }
APIs api_table = { fn1, fn2, fn3 };
// client.cc
#include "libfoo.h"
...
void *foo_handle = dlopen("libfoo.so", RTLD_LAZY);
if (!foo_handle) {
return false; // library not present
}
APIs *table = dlsym(foo_handle, "api_table");
table->api1(); // calls fn1
void *p = table->api2(42); // calls fn2
long x = table->api3(1, p); // calls fn3
P.S. dlsymとポインタを使用してAPI関数に個別にアクセスすると、自体がメモリの破損やクラッシュにつながりません。ほとんどの場合、バグがあります。
編集:
第三者のライブラリでもまったく同じ手法を使用できます。 libdrmaa_wrapper.so
を作成し、api_table
を入れます。ラッパーをlibdrmaa.so
と直接リンクします。
メイン実行可能ファイルでは、dlopen("libdrmaa_wrapper.so", RTLD_NOW)
です。このdlopen
は、実行時にlibdrmaa.so
が存在する場合にのみ成功し、api_table
で使用したすべてのAPI関数を提供します。成功した場合は、1回のdlsym
呼び出しでAPI全体にアクセスできます。実行時にこのライブラリをロードするためのコード
Class DynLib
{
/* All your functions */
void fun1() {};
void fun2() {};
.
.
.
}
DynLib* getDynLibPointer()
{
DynLib* x = new Dynlib;
return x;
}
使用dlopen()
の種類以下
とdooopen()を呼び出してfoo_handleを取得するにはどうすればよいですか?私はそれが自動的にlibAPI.soと言う共有オブジェクトをロードするのだろうか? – sud03r
実際にはライブラリを開くためにdlopen()が使用されています... .. nyways私はur pointを取得しましたが、ライブラリにAPI構造体がある場合にのみ機能します。サードパーティでは期待できませんライブラリ..私はsungrid api libdrmaa.soを使用しようとしています.. – sud03r
テーブルへのポインタを取得する代わりに、呼び出されたときにテーブルへのポインタを返す関数へのポインタを取得できます。これにより、他の関数が呼び出される前にプラグインを初期化したり、動的にテーブルを作成したりすることができます。 – CesarB