Domanda

Qual è il modo più semplice e sicuro per chiamare una funzione da una libreria / DLL condivisa? Sono per lo più interessati a fare questo su Linux, ma sarebbe meglio se ci fosse un modo indipendente dalla piattaforma.

Qualcuno potrebbe fornire il codice esempio per mostrare come fare i seguenti lavori, in cui l'utente ha compilato la sua propria versione di foo in una libreria condivisa?

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

A proposito, so come compilare il lib condivisa (foo.so), ho solo bisogno di sapere un modo semplice per caricarlo in fase di esecuzione.

È stato utile?

Soluzione

Nota: Si passa oggetti C ++ (in questo caso le stringhe STL) intorno chiamate di libreria. V'è alcuno standard C ++ ABI a questo livello , quindi o cercare di evitare di passare oggetti C ++ in giro, o assicurarsi che sia la libreria e il programma sono stati costruiti con lo stesso compilatore (idealmente lo stesso compilatore sulla stessa macchina, per evitare sorprese legati alla configurazione sottili.)

Non dimenticare di dichiarare i vostri metodi esportati extern "C" all'interno del codice della libreria.

È possibile che questo essendo stato detto, qui è del codice attuare quello che hai detto che si vuole raggiungere :

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

Puoi abstract questa ulteriore :

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

Altri suggerimenti

LoadLibrary è una funzione di Windows per DLL caricamento. È possibile verificare la presenza di simbolo dell'esistenza con GetProcAddress . Su Linux / Unix desideri dlopen / dlsym . Per fare questo in cross-platform, si potrebbe scrivere una funzione che chiama uno di questi metodi che utilizzano pre-processore, quindi, qualcosa di simile a:

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

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

#endif
}

Questo è un modo per raggiungere questo genere di cose. Si potrebbe anche farlo, includendo una diversa intestazione nel proprio albero dei sorgenti per specifiche implementazioni di piattaforma di funzioni. Questo è probabilmente un modo migliore. In entrambi i casi l'idea è di estratto API sottostante.

Su Linux è necessario utilizzare dlsym . Vedere un esempio alla fine della pagina. Sulla Finestra:. GetProcAddress

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top