Question

Quelle est la meilleure et la plus sûre d'appeler une fonction à partir d'une bibliothèque partagée / dll? Je suis surtout intéressé à faire sur linux, mais il serait mieux s'il y avait un moyen de plate-forme indépendante.

Quelqu'un pourrait-il fournir le code exemple pour montrer comment faire les travaux suivants, où l'utilisateur a compilé sa propre version de foo dans une bibliothèque partagée?

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

BTW, je sais comment compiler le répertoire lib partagé (foo.so), je veux juste savoir un moyen facile de le charger à l'exécution.

Était-ce utile?

La solution

NOTE: Vous passez des objets C ++ (dans ce cas des chaînes STL) autour des appels de bibliothèque. Il est pas de norme C ++ ABI à ce niveau , donc soit essayer de éviter les objets passant C ++ autour, ou assurez-vous que les deux votre bibliothèque et votre programme ont été construits avec le même compilateur (idéalement le même compilateur sur la même machine, afin d'éviter des surprises liées à la configuration subtile.)

Ne pas oublier de déclarer vos méthodes exportées extern "C" dans votre code de la bibliothèque.

Le ci-dessus ayant été dit, voici un code mise en œuvre de ce que vous avez dit que vous voulez réaliser :

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

Vous pouvez résumé cette autre :

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

Autres conseils

LoadLibrary est une fonction de Windows pour les DLL de chargement. Vous pouvez vérifier l'existence de symboles avec GetProcAddress . Sous Linux / Unix, vous voulez dlopen / dlsym . Pour ce faire, en cross plate-forme, vous pouvez écrire une fonction qui appelle l'une de ces méthodes à l'aide de pré-processeur, donc, quelque chose comme:

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

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

#endif
}

Ceci est un moyen d'atteindre ce genre de chose. Vous pouvez aussi le faire en incluant un en-tête dans votre propre arbre source pour les implémentations de plates-formes spécifiques de fonctions. Ceci est probablement une meilleure façon. Dans les deux cas, l'idée est de faire abstraction de l'API sous-jacente.

Sur Linux vous devez utiliser dlsym . Voir un exemple à la fin de la page. Sur la fenêtre. GetProcAddress

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top