Pregunta

¿Cuál es la forma más fácil y más seguro para llamar a una función de una biblioteca / DLL compartida? Me interesa sobre todo en hacer esto en Linux, pero sería mejor si hubiera una manera independiente de la plataforma.

Podría alguien proporcionar el código ejemplo para mostrar cómo hacer el siguiente trabajo, en el que el usuario ha compilado su propia versión de foo en una biblioteca compartida?

// 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;
}

Por cierto, sé cómo compilar la librería compartida (foo.so), sólo necesito saber una manera fácil de cargar en tiempo de ejecución.

¿Fue útil?

Solución

Nota: está de paso C ++ objetos (en este caso las cadenas STL) alrededor de las llamadas bibliotecas. Hay no estándar C ++ ABI a este nivel , así que o tratar de evitar el paso C ++ objetos alrededor, o asegurar que tanto su biblioteca y su programa han sido construidos con el mismo compilador (idealmente el mismo compilador en la misma máquina, para evitar sorpresas relacionadas con la configuración sutiles.)

No se olvide de declarar sus métodos exportados extern "C" dentro de su código de la biblioteca.

Lo anterior después de haber sido dicho, aquí es algún código implementación de lo que ha dicho que quiere lograr

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

Puede Resumen Este más

#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);

Otros consejos

LoadLibrary es una función de Windows para cargar archivos DLL. Puede comprobar si el símbolo de la existencia con GetProcAddress . En Linux / Unix desea dlopen / dlsym . Para hacer esto en varias plataformas, que podría escribir una función que llama a cualquiera de estos métodos que utilizan pre-procesador, así, algo como:

int loadlibrary(char* library)
{
#ifdef _WIN32
    /* do windows code */

#endif
#ifdef _LINUX
    /* do linux code */

#endif
}

Esta es una forma de lograr este tipo de cosas. También puede hacerlo mediante la inclusión de un encabezado diferente en su propio árbol de código fuente para las implementaciones específicas de la plataforma de funciones. Esta es probablemente una mejor manera. En cualquier caso, la idea es hacer abstracción de la API subyacente.

En Linux es necesario utilizar dlsym . Ver un ejemplo al final de la página. En Ventana:. GetProcAddress

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top