共有ライブラリから関数を呼び出す方法は?
-
22-09-2019 - |
質問
共有ライブラリ / DLLから関数を呼び出す最も簡単で安全な方法は何ですか?私はこれをLinuxで行うことにほとんど興味がありますが、プラットフォームに依存しない方法があればそれが良いでしょう。
ユーザーが自分のバージョンをコンパイルした場合、次の作業を作成する方法を示すための例コードを誰かが提供できますか? foo
共有ライブラリに?
// function prototype, implementation loaded at runtime:
std::string foo(const std::string);
int main(int argc, char** argv) {
LoadLibrary(argv[1]); // loads library implementing foo
std::cout << "Result: " << foo("test");
return 0;
}
ところで、私は共有Libをコンパイルする方法を知っています(foo.so
)、実行時に簡単にロードする方法を知る必要があります。
解決
ノート: ライブラリコールの周りにC ++オブジェクト(この場合はSTL文字列)を渡しています。がある 標準のC ++なし アビ このレベルで, 、したがって、C ++オブジェクトを渡すことを避けないようにするか、ライブラリとプログラムの両方が同じコンパイラで構築されていることを確認してください(理想的には同じマシンの同じコンパイラが微妙な構成関連の驚きを避けてください。)
するのを忘れないで エクスポートされた方法を宣言します extern "C"
ライブラリコード内。
上記は言われた、ここに あなたが達成したいと言ったことを実装するいくつかのコード:
typedef std::string (*foo_t)(const std::string);
foo_t foo = NULL;
...
# ifdef _WIN32
HMODULE hDLL = ::LoadLibrary(szMyLib);
if (!hDll) { /*error*/ }
foo = (foo_t)::GetProcAddress(hDLL, "foo");
# else
void *pLib = ::dlopen(szMyLib, RTLD_LAZY);
if (!pLib) { /*error*/ }
foo = (foo_t)::dlsym(pLib, "foo");
# endif
if (!foo) { /*error*/ }
...
foo("bar");
...
# ifdef _WIN32
::FreeLibrary(hDLL);
# else
::dlclose(pLib);
# endif
あなたはできる これをさらに抽象化します:
#ifdef _WIN32
#include <windows.h>
typedef HANDLE my_lib_t;
#else
#include <dlfcn.h>
typedef void* my_lib_t;
#endif
my_lib_t MyLoadLib(const char* szMyLib) {
# ifdef _WIN32
return ::LoadLibraryA(szMyLib);
# else //_WIN32
return ::dlopen(szMyLib, RTLD_LAZY);
# endif //_WIN32
}
void MyUnloadLib(my_lib_t hMyLib) {
# ifdef _WIN32
return ::FreeLibrary(hMyLib);
# else //_WIN32
return ::dlclose(hMyLib);
# endif //_WIN32
}
void* MyLoadProc(my_lib_t hMyLib, const char* szMyProc) {
# ifdef _WIN32
return ::GetProcAddress(hMyLib, szMyProc);
# else //_WIN32
return ::dlsym(hMyLib, szMyProc);
# endif //_WIN32
}
typedef std::string (*foo_t)(const std::string);
typedef int (*bar_t)(int);
my_lib_t hMyLib = NULL;
foo_t foo = NULL;
bar_t bar = NULL;
...
if (!(hMyLib = ::MyLoadLib(szMyLib)) { /*error*/ }
if (!(foo = (foo_t)::MyLoadProc(hMyLib, "foo")) { /*error*/ }
if (!(bar = (bar_t)::MyLoadProc(hMyLib, "bar")) { /*error*/ }
...
foo("bar");
bar(7);
...
::MyUnloadLib(hMyLib);
他のヒント
LoadLibrary DLLをロードするためのWindows関数です。シンボルの存在を確認できます GetProcAddress. 。 Linux/Unixであなたが望む dlopen/dlsym. 。クロスプラットフォームでこれを行うには、PreProcessorを使用してこれらのメソッドのいずれかを呼び出す関数を書くことができます。
int loadlibrary(char* library)
{
#ifdef _WIN32
/* do windows code */
#endif
#ifdef _LINUX
/* do linux code */
#endif
}
これは、この種のことを達成する1つの方法です。また、機能の特定のプラットフォーム実装のために、独自のソースツリーに別のヘッダーを含めることでそれを行うこともできます。これはおそらくより良い方法です。どちらの場合でも、アイデアは基礎となるAPIから抽象化することです。
Linuxで使用する必要があります dlsym. 。ページの最後の例を参照してください。ウィンドウ上: GetProcAddress.