19

一部で共有ライブラリを使用するアプリケーションがあります。これらのライブラリはコンパイル時にリンクされます。
実行時に、ローダーは共有オブジェクトが にあることを期待します。LD_LIBRARY_PATH見つからない場合、アプリケーション全体が「共有ライブラリをロードできません」というエラーでクラッシュします。クライアントがライブラリを持っているという保証はないことに注意してください。適切なエラーメッセージを残すアプリケーションも、独立した部分が正しく機能するはずです。

この目的のために、私は共有ライブラリの API を使用していますdlsym()dlopen()これに関する問題は、API に多くの関数がある場合、それらに個別にアクセスする必要dlsym()があり、私の場合はメモリの破損とコードのクラッシュにつながる ptr を使用する必要があることです。

これに代わるものはありますか?

4

5 に答える 5

32

この問題の一般的な解決策は、関数ポインターのテーブルを宣言し、それを見つけるために単一の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

PS dlsymとポインタを使用してAPI関数に個別にアクセスしても、それ自体ではメモリの破損やクラッシュは発生しません。ほとんどの場合、バグがあります。

編集:
サードパーティのライブラリでこれとまったく同じ手法を使用できます。を作成し、libdrmaa_wrapper.soそれに入れますapi_table。ラッパーをに直接リンクしますlibdrmaa.so

メインの実行可能ファイルでは、dlopen("libdrmaa_wrapper.so", RTLD_NOW)。これは、実行時に存在し、で使用したすべてのAPI関数を提供するdlopen場合にのみ成功します。成功した場合は、1回の呼び出しでAPI全体にアクセスできます。libdrmaa.soapi_tabledlsym

于 2009-07-01T07:11:01.200 に答える
2

以下のタイプのコードを使用

Class DynLib
{
    /* All your functions */
    void fun1() {};
    void fun2() {};
    .
    .
    .
}

DynLib* getDynLibPointer()
{
    DynLib* x = new Dynlib;
    return x;
}

dlopen()実行時にこのライブラリをロードするために使用します。DynLibオブジェクトを返す使用dlsym()および呼び出し。このオブジェクトから、すべての関数 jst に.....getDynLibPointer()としてアクセスできます。obj.fun1()

これはもちろん、以前に提案された struct メソッドの C++ スタイルです。

于 2013-05-04T06:58:06.850 に答える