Как вызвать функцию из общей библиотеки?
-
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;
}
Кстати, я знаю, как скомпилировать общую либерацию (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 это функция Windows для загрузки DLL. Вы можете проверить наличие символов с GetProcadDress. Анкет На Linux/Unix вы хотите Длопен/DLSYM. Анкет Чтобы сделать это на кросс-платформе, вы можете написать функцию, которая вызывает любой из этих методов, используя допроцессор, поэтому, что-то вроде:
int loadlibrary(char* library)
{
#ifdef _WIN32
/* do windows code */
#endif
#ifdef _LINUX
/* do linux code */
#endif
}
Это один из способов достичь такого рода вещей. Вы также можете сделать это, включив другой заголовок в собственное дерево источника для конкретных реализаций платформ функций. Это, наверное, лучший способ. В любом случае идея состоит в том, чтобы абстрагировать из базового API.
На Linux вам нужно использовать DLSYM. Анкет См. Пример в конце страницы. В окне: GetProcadDress.