43 votes

Création d'un système de modules (chargement dynamique) en C

Comment procéder pour charger du code C compilé au moment de l'exécution, puis appeler des fonctions en son sein? Pas comme simplement appeler exec ().

EDIT: Le programme qui charge le module est en C.

48voto

bortzmeyer Points 12246

dlopen est le chemin à parcourir. Voici quelques exemples:

Chargement d'un plugin avec dlopen:

#include        <dlfcn.h>
...
int
main (const int argc, const char *argv[])
{

  char *plugin_name;
  char file_name[80];
  void *plugin;
  ...
  plugin = dlopen (file_name, RTLD_NOW);
  if (!plugin)
  {
     fatal ("Cannot load %s: %s", plugin_name, dlerror ());
  }

La compilation ci-dessus:

% cc  -ldl -o program program.o

Ensuite, en supposant que cette API pour les plugins:

/* The functions we will find in the plugin */
typedef void (*init_f) ();
init_f init;
typedef int (*query_f) ();
query_f query;

Trouver l'adresse de la fonction init() dans le plugin:

init = dlsym (plugin, "init");
result = dlerror ();
if (result)
{
   fatal ("Cannot find init in %s: %s", plugin_name, result);
}
init ();

Avec l'autre fonction query(), qui retourne une valeur:

query = dlsym (plugin, "query");
result = dlerror ();
if (result)
{
    fatal ("Cannot find query in %s: %s", plugin_name, result);
}
printf ("Result of plugin %s is %d\n", plugin_name, query ());

Vous pouvez récupérer l'exemple complet en ligne.

38voto

Robert Gamble Points 41984

Sous Linux / UNIX, vous pouvez utiliser les fonctions POSIX dlopen / dlsym / dlerror / dlclose pour ouvrir dynamiquement des bibliothèques partagées et accéder aux symboles (y compris les fonctions) qu'elles fournissent, consultez la page de manuel pour plus de détails.

9voto

erisu Points 118

Le voir, cette question a été répondu, mais la pensée d'autres personnes intéressées par le sujet peuvent apprécier une plate-forme de l'exemple d'un vieux plugin en fonction de l'application. L'exemple fonctionne sur win32 et linux, et seaches et appelle une fonction appelée 'constructeur' dans l'chargé dynamiquement .donc ou .dll spécifiée dans le fichier argument. L'exemple est en c++, mais la procédure devrait être la même pour les c de.

//firstly the includes
#if !defined WIN32
   #include <dlfcn.h>
   #include <sys/types.h>
#else
   #include <windows.h>
#endif

//define the plugin's constructor function type named PConst
typedef tcnplugin* (*PConst)(tcnplugin*,tcnplugin*,HANDLE);

//loads a single specified tcnplugin,allmychildren[0] = null plugin
int tcnplugin::loadplugin(char *file) {
    tcnplugin *hpi;
#if defined WIN32               //Load library windows style
    HINSTANCE hplugin=LoadLibrary(file);
    if (hplugin != NULL) {
            PConst pinconstruct = (PConst)GetProcAddress(hplugin,"construct");
#else                                   //Load it nix style
    void * hplugin=dlopen(file,RTLD_NOW);
    if (hplugin != NULL) {
            PConst pinconstruct = (PConst)dlsym(hplugin,"construct");
#endif   
            if (pinconstruct != NULL) { //Try to call constructor function in dynamically loaded file, which returns a pointer to an instance of the plugin's class
                    hpi = pinconstruct(this, this, hstdout);
            } else {
                    piprintf("Cannot find constructor export in plugin!\n");
                    return 0;
            }
    } else {
            piprintf("Cannot open plugin!\n");
#if !defined WIN32
            perror(dlerror());
#endif
            return 0;
    }
    return addchild(hpi); //add pointer to plugin's class to our list of plugins
}

Pourrait aussi être mentionné que si le module qui est des fonctions que vous souhaitez appeler, est écrit en c++, il faut déclarer la fonction avec extern "C", tels que:

extern "C" pcparport * construct(tcnplugin *tcnptr,tcnplugin *parent) {
    return new pcparport(tcnptr,parent,"PCPARPORT",0,1);
}

3voto

lazyden Points 264

Vous pouvez également regarder cpluff . Il s'agit d'une bibliothèque de gestion de plugins sur pure c.

2voto

Andrew Ross Points 61

Si vous êtes prêt à envisager le cadre, Qt fournit QPluginLoader: http://qt-project.org/doc/qt-4.8/qpluginloader.html

Si vous avez besoin de plus de précision, de contrôle, Qt fournit également un moyen de charger des bibliothèques à la volée avec QLibrary: http://qt-project.org/doc/qt-4.8/qlibrary.html

Mieux encore, ce sont portable sur l'ensemble des plates-formes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X