Architecture de plugin en C utilisant libdl

Je me suis mis à écrire un petit framework IRC en C que je vais maintenant développer avec quelques fonctionnalités essentielles – mais au-delà, j’aimerais qu’il soit extensible avec des plugins!

Jusqu’à présent, chaque fois que j’écrivais quelque chose en rapport avec IRC (et j’en écrivais beaucoup, dans environ 6 langues différentes maintenant … j’ai pris feu!) Et que je mettais réellement en place une architecture de plug-in, c’était à eu des installations pour faire (lire: abuser) donc, comme brouiller un fichier de script entier via eval dans Ruby (mauvais!).

Maintenant, je veux abuser de quelque chose en C!

En gros, il y a trois choses que je pourrais faire

  1. définir un langage de script simple à l’intérieur de mon programme
  2. utiliser un existant, incorporer un interprète
  3. utiliser libdl pour charger les modules * .so au moment de l’exécution

J’aime le troisième et évite plutôt les deux autres options si possible. Peut-être que je suis un masochiste, mais je pense que cela pourrait être à la fois amusant et utile pour l’apprentissage.

En pensant logiquement, la “chaîne de la douleur” évidente serait (du plus bas au plus élevé) 2 -> 1 -> 3, pour la simple raison que libdl traite du code brut qui peut (et va) exploser à la face le plus souvent. .

Donc, cette question s’adresse à vous, chers utilisateurs de stackoverflow, pensez-vous que libdl est à la hauteur de cette tâche, ou même d’une pensée réaliste?

    libdl est très bien adapté aux architectures plug-in – dans certaines limites :-). Il est utilisé beaucoup pour exactement ce genre de but dans beaucoup de logiciels différents. Cela fonctionne bien dans les situations où il existe une API / interface bien définie entre le programme principal et le plug-in, et un certain nombre de plug-ins différents implémentant la même API / interface. Par exemple, votre client IRC peut avoir des plug-ins qui implémentent des passerelles vers différents protocoles de messagerie instantanée (Jabber, MSN, Sametime, etc.). Tous sont très similaires. Vous pouvez donc définir une API avec des fonctions telles que “envoyer un message”. “,” check for reply “etc. – et écrivez un ensemble de plug-ins qui implémentent chacun un protocole différent.

    La situation dans laquelle cela fonctionne moins bien est celle dans laquelle vous souhaitez que les plug-ins apportent des modifications arbitraires au comportement du programme principal – par exemple, les plug-ins Firefox peuvent modifier le comportement des tabs du navigateur, ainsi que leur apparence. , append / supprimer des boutons, etc. Ce type de tâche est beaucoup plus facile à réaliser dans un langage dynamic (d’où la raison pour laquelle une grande partie de Firefox est implémentée en javascript), et si c’est le type de personnalisation que vous souhaitez, vous aurez peut-être intérêt à utiliser votre option beaucoup de votre interface utilisateur dans le langage de script …

    dlopen() / dlsym() sont probablement le moyen le plus simple. Un code pseudo stupide:

     int run_module(const char *path, char **args) { void *module; void (*initfunc)(char **agrs); int rc = 0; module = dlopen(path, RTLD_NOW); if (module == NULL) err_out("Could not open module %s", path); initfunc = dlsym(module, "module_init"); if (initfunc == NULL) { dlclose(module); err_out("Could not find symbol init_func in %s", path); } rc = initfunc(args); dlclose(module); return rc; } 

    Bien sûr, vous voudriez beaucoup plus de contrôle d’erreur, ainsi que du code qui a réellement fait quelque chose d’utile 🙂 Il est cependant extrêmement facile et pratique d’écrire une architecture de plug-in autour de la paire et de publier une spécification simple. pour que les autres fassent de même.

    Vous voudriez probablement quelque chose de plus dans les lignes de load_module() , la load_module() ci-dessus ne fait que charger le load_module() de la load_module() , cherche un point d’entrée et se bloque jusqu’à la load_module() ce point.

    Cela ne veut pas dire que l’écriture de votre propre langage de script est une mauvaise idée. Les gens pouvaient écrire des filtres complexes, des répondeurs, etc. sans avoir à subir beaucoup de problèmes. Peut-être que les deux seraient une bonne idée. Je ne sais pas si vous souhaitez un interprète LUA à part entière. Peut-être pourriez-vous proposer quelque chose qui simplifie la prise d’actions basées sur des expressions régulières.

    Néanmoins, les modules enfichables ne vous simplifieront pas la vie, ils vous aideront également à développer une communauté de personnes développant des outils autour de vos projets.

    De nombreux programmes C existants utilisent dlopen() / dlsym() pour implémenter une architecture de plug-in (y compris plusieurs architectures liées à IRC); alors oui, c’est vraiment à la hauteur.