Question

Quelles sont les méthodes “normales” de création de plug-ins dans les langages compilés (C # / C / C ++ / D)? Je suis particulièrement intéressé par les approches agnostiques des langues, mais les spécificités linguistiques ne sont pas inacceptables.

Pour le moment, les approches plug-in «compilation» (il suffit d'inclure le code ou tout fonctionne) sont valides, mais les éléments pouvant migrer vers une approche plus dynamique sont préférés.

En ce qui concerne le type d’exécution, je suis plus intéressé par la mécanique du chargement du plug-in que par la conception de l’interface plug-in / app

EDIT: BTW le plugin serait un esclave et non un maître. L'action de base d'un plug-in serait que, dans une situation donnée, il soit appelé à "faire ce qu'il a à faire" et recevoir un objet d'environnement qu'il devrait utiliser pour obtenir ce dont il a besoin pour fonctionner.

Était-ce utile?

La solution

Pour les langages compilés (où compilé signifie que le programme s'exécute en tant qu'exécutable natif, sans aucune machine virtuelle), vous devez utiliser une sorte d'approche de bibliothèque partagée spécifique à la plate-forme. Sous Windows, cela signifie qu’il faut utiliser des DLL.

Vous définissez votre interface de plug-in en termes d'un ensemble de fonctions (avec des noms, des arguments et des conventions d'appel spécifiques). Ensuite, vous chargez les adresses des fonctions dans la bibliothèque partagée et allez en ville. Sous Windows, cela signifie qu’il faut utiliser GetProcAddress () . , puis en transmettant la valeur renvoyée à un pointeur de fonction du type approprié en C ou à l’équivalent dans la langue que vous utilisez.

Une autre option souhaitable ou non consiste à exécuter une machine virtuelle pour une autre langue à partir de votre application native et à faire en sorte que les plug-ins soient codés pour cette langue. Par exemple, vous pouvez exécuter une machine virtuelle Python avec CPython et charger dynamiquement des modules Python.

Autres conseils

Mono.Addins semble être une bonne solution pour .NET. Je crois que cela inclut une API qui vous permet de télécharger des plugins (ou des compléments) à partir d’un dépôt et de les charger dynamiquement dans un assemblage en cours d’exécution.

J'ai constaté que les composants les plus difficiles concernant les plug-ins sont les suivants: les trouver, résoudre leurs dépendances et gérer les problèmes de version. La façon dont vous gérez ces problèmes devrait être claire pour vous et vos auteurs de plug-in. Si vous vous trompez, cela ne causera pas de douleur. Je regarderais des langages de script et des applications qui utilisent des plugins pour avoir des idées sur ce qui marche bien.

Les constructeurs statiques sont le plus souvent, "intelligents". dans le mauvais sens. Puisque vous allez devoir charger (C / C ++: dlopen et amis sous Linux) les plugins un à la fois (dans le cas dynamique), vous pouvez aussi les initialiser manifestement que vous le feriez. Entre autres choses, cela peut vous donner l’opportunité de rejeter des plugins sans les API attendues.

Remarque, vous n'avez pas besoin d'utiliser des bibliothèques de chargement dynamiques pour les plugins. D'autres mécanismes peuvent également être utilisés: mémoire partagée, sockets, etc ...

Cela dépend vraiment de ce que vous voulez faire. Le modèle Unix habituel, vu dans Emacs et Gimp, consiste à écrire un programme qui consiste en un petit composant compilé qui expose les fonctionnalités essentielles qu'un composant interprété utilise pour tout faire. Les éléments Pluglins offrant de nouvelles fonctionnalités pouvant être intégrées à l'application sont simples, mais vous devez faire preuve de la plus grande souplesse dans les primitives que vous fournissez pour que cela soit possible. À l'extrême opposé, imaginez un éditeur de photos pouvant enregistrer dans plusieurs formats. Vous souhaitez autoriser les personnes à écrire leurs propres gestionnaires de format de fichier. Cela nécessite que votre code utilise un simple ensemble de primitives, puis qu'il sélectionne une implémentation lors de l'exécution. En straight (Unix) C, utilisez dlopen, en C ++, utilisez extern C, ce qui limite ce que vous pouvez faire et dlopen. En Objective-C, vous avez une classe à faire pour vous. Dans le premier cas, vous créez ou réutilisez un interprète afin que vous puissiez le faire comme vous le souhaitez.

Pour un plug-in de type esclave où chaque plug-in encapsule une implémentation différente d'un ensemble commun de fonctions, je voudrais simplement déposer les DLL dans un dossier de plug-in connu de l'application hôte (par exemple, "c: \ fichiers de programme \ myapp \ plugins), puis appelez les DLL de l’hôte via Reflection.

Vous pouvez effectuer une sorte de processus d’enregistrement complexe lors de l’installation de chaque DLL, mais je n’ai jamais rencontré de problème avec l’approche plugins-in-one-folder.

Edition: pour ce faire en C #, il vous suffit d'ajouter une classe publique à la DLL (nommé "Plugin" ou autre) et d'y implémenter les fonctions nécessaires. À partir de votre hôte, vous créez ensuite un objet de type Plugin et appelez ses méthodes (toutes à l’aide de Reflection).

Les interfaces avec un registre vide (EventSource) semblent bien fonctionner - voir IHttpModule.Init (HttpApplication ) pour un exemple.

Ceci permet à l'auteur de l'application (qui contrôle EventSource) d'ajouter des événements en fonction des besoins, sans avoir besoin d'étendre l'interface IPlugin (conduisant inévitablement à IPluginEx, IPlugin2, IPlugin2Ex, etc.)

L’approche que j’ai utilisée (en .NET) consiste à demander à l’hôte de faire un appel initial au plug-in (via Reflection), en démarrant le plug-in et en transmettant une référence à l’hôte que celui-ci enregistre. Le plug-in appelle ensuite les méthodes sur l'hôte (également par réflexion) si nécessaire.

Je pense qu'avec la plupart des plug-ins, les appels seraient généralement passés dans l'autre sens (c'est-à-dire que l'hôte appellerait le plug-in si nécessaire). Dans mon cas, les plugins eux-mêmes avaient des éléments d'interface utilisateur qui devaient utiliser les fonctionnalités de l'hôte.

Mis à part les problèmes d’implémentation de module de bas niveau (par exemple, les DLL Windows et les problèmes d’implémentation), un moteur de jeu que j’utilise a simplement une fonction d’enregistrement global dans les DLL et tente de le trouver et de l’appeler sur chaque dll du répertoire du plugin. la fonction d’enregistrement effectue la comptabilité nécessaire pour exposer les fonctionnalités.

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