Bonjour
Je souhaitrai savoir comment je peux utiliser des plugin '.so' contenant des classes C++, j 'ai réussi a créer des plugin avec des fonction dedans mais pas des classes.
Merci
Bonjour
Je souhaitrai savoir comment je peux utiliser des plugin '.so' contenant des classes C++, j 'ai réussi a créer des plugin avec des fonction dedans mais pas des classes.
Merci
Gros sujet! Si ton ".so" est compilé avec le même compilateur (même version) et les mêmes options de compilation que ton application hôte, il n'y a presque aucune différence avec une bibliothèque statique. Par contre, si il y a le moindre changement, les choses se gâtent: c'est l'un des points faibles du C++ que de ne pas avoir une ABI (spécification binaire) bien définie et suivie par tous les compilateurs et toutes leurs versions, et les plugins en C++ sont une gageure.
Qu'est-ce que tu cherches à faire exactement?
Carl
Merci pour ta réponse,
en faite, j'ai trois classes qui servent a prendre n'importe quel tableau ou vector de n'importe quel type et le trie.
c'est une application graphique, ce que je souhaite c'est que l'application soit séparé des classes de tri et je veux aussi pouvoir par la suite rajouter de nouvelles classes et tous ca sous forme de plugin que je charge par un bouton charger.
Je crois que je ne vois pas l'intérêt d'avoir ces algorithmes de tri dans des plugins, s'ils ne diffèrent que par les types de données qu'ils peuvent trier. En effet, chaque bout de code qui devra utiliser un "nouveau" tri parce qu'il a un type pour lequel l'un des tris existants ne fait pas l'affaire devra de toute façon fournir cette implémentation de tri, sous peine de ne pas compiler.
Dans ton cas de figure, tu devrais plutôt fournir un ou deux templates d'algorithmes de tri dans un header de ton système de base et donner accès à ces headers à ceux qui fourniront des plugins. Ou alors ils utilisent tout simplement std::sort()...
J'ai peut-être mal compris ton idée. Tu peux m'en dire plus sur tes algos de tri et sur tes classes?
Carl
Bain l'interet des plugin n'est pas immediat, plutard si une personne veux utiliser son propre algorithme, elle le cree et le compile en tant que .so et le charge via l'appliction et ainsi il pourra utiliser son algorithme dans l'application.
Le principe n'est pas compliqué, c'est le mettre en application qui l'est:
Tu dois créer une bibliothèque commune entre ton application et ton plugin. Cette biblio ne contiendra que des interfaces (si tu ne sais pas ce qu'est une interface ou si tu te dis "oh les interfaces ça existe pas en C++" il est temps d'aller potasser). A noter au passage qu'à priori cette biblio sera toujours header only. Tout dialogue entre ton applic et un plugin ou inversément se fait obligatoirement via des interfaces et rien d'autre point barre.
Après, à partir du moment où tu sais appeler une fonction dans une librairie dynamique, il suffit de définir une fonction du style:
Et la tu sais tout faire, oui tout, on est dans du pur orienté objet alors quel que soit le ou les problèmes auquel tu pourrais être confronté il y a forcément une solution, mais ça relève de la conception OO.
Code : Sélectionner tout - Visualiser dans une fenêtre à part TonInterface* givemeyourinterface();
Pour les interfaces je vais m'informer sur ca.
Par contre, j'ai réalisé un exmple très simple qui illustre mon problème, et j'ai la même erreur.
mon plugin: test.so
mon programme principale
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 extern "C++" { #include <stdio.h> template< class classTest > void chien( void ) { printf( "\\wof wof/\n" ); printf( " \\...../\n" ); printf( " ...\n" ); printf( " .\n" ); printf( " <I________/\n" ); printf( " || ||\n" ); } // chien() }
erreur:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 #include <iostream> #include <dlfcn.h> using namespace std; typedef void ( * FCT ) ( void ); int main( void ) { void* dlobj; if( dlobj = dlopen( "test.so", RTLD_LAZY ) ) { FCT fct_appel = ( FCT ) dlsym( dlobj, "chien" ); ( * fct_appel )< int >(); } return 0; } // main()
Merci
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 main.cxx: In function «int main()": main.cxx:15: erreur: expected primary-expression before «int" main.cxx:15: erreur: expected `;' before «int" make: *** [main.o] Erreur 1
Oula, tu n'as pas bien compris comment fonctionnent les templates on dirait.
Oublie définitivement les fonctions template pour ton plugin, d'autant plus que dans le cas présent ça n'a vraiment aucune utilité.
PS: je sais que certains tutos expliquent qu'il faut utiliser extern C quelque chose pour la déclaration de la fonction dans le plugin, mais ça n'exclu en rien que le contenu de cette fonction soit écrit en C++.
Ok je ne sais peut etre pas comment ca fonctionne les templates, mais dis moi ou est ce qu'elle est l'erreur dans mon exemple.
Il est impossible d'appeler un fonction par l'intermédiaire d'un pointeur de fonction en lui spécifiant une liste de paramètres template.
Ce qui se traduit par -> bon sang, mais qu'est ce qu'elle fout la cette fonction template? Utilise des fonctions simples, ça fera exactement la même chose et ça aura peut-être une chance de fonctionner...
Merci pour ta réponse.
Mais alors comment est ce que je peux faire pour utiliser des classe dans mon programme principale en supposant que ces classes sont définies avec des templates ?
Tu ne peux tout simplement pas
Les templates ne peuvent pas et ne pourront jamais se propager dans un programme déja compilé. La seule méthode qui permette de créer des plugins est le late binding, dit autrement avec une vision un peu plus large: le polymorphisme objet. Oui je sais, ce n'est pas la technique de programmation de prédilection en C++ mais faudra faire avec.
Petite précision : Il est n'est possible d'exporter ainsi un template, mais rien n'empêche d'exporter une instance d'un template, qui est une classe/fonction comme une autre.
Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.
Ce qui:
- n'est susceptible de fonctionner qu'avec les fonctions template, pas les classes (ça demanderait une réflexion plus poussée mais ça me semble correct)
- a un interet proche du néant absolu (un peu de sucre syntaxique sans plus)
- va rendre hyper drole l'appel de la fonction (tu la connais la norme de nommage des instances de template dans les bibliothèques dynamiques?)
- a l'énorme avantage de s'éloigner fortement du concept de base que j'essaie d'expliquer depuis quatre messages, et tout le monde sait qu'il est inutile de connaitre les concepts de base avant d'inventer des trucs nouveaux
Hello zais_ethael et les autres,
Je me fais un peu l'avocat du diable, mais le problème, c'est que même en définissant une interface abstraite, il n'y a aucune garantie que deux compilateurs différents vont implémenter la résolution dynamique de la même façon. Même si les deux utilisent des vtables, les fonctions ne seront peut-être pas ordonnées de la même façon.
Concession: dans la pratique, beaucoup de compilateurs sous Windows se conforment à ce que fait Visual C++, mais sous d'autres OS, rien n'est moins sûr (ce qui explique pourquoi le C++ reste anecdotique sur Linux comparé au C).
Bref. La seule chose qui marche à coup sûr, ce sont les fonctions toutes simples déclarées avec la convention C. Et c'est pénible!
Carl
N'importe quel template peut-etre instancié explicitement, et donc exporté.
Pour le développeur qui l'utilise, aucun avantage non. Le template sera figé. Pour le développeur de la fonction en revanche, ça peut lui épargner pas mal de réécriture de code.- a un interet proche du néant absolu (un peu de sucre syntaxique sans plus)
Hum, l'appel devrait rester le même, pourquoi changerait-il ?- va rendre hyper drole l'appel de la fonction (tu la connais la norme de nommage des instances de template dans les bibliothèques dynamiques?)
- a l'énorme avantage de s'éloigner fortement du concept de base que j'essaie d'expliquer depuis quatre messages, et tout le monde sait qu'il est inutile de connaitre les concepts de base avant d'inventer des trucs nouveauxC'est vrai que c'est rare d'avoir ce type d'utilisation. On rabâche que les templates, sont inline, sont dans des headers et des inl, sont pas dans des dll, car c'est le cas... 99% du temps.
Merci pour toutes vos réponses, Vous auriez une solution alors pour mon cas, je suis entrain de faire un projet, et il m'est demandé d'avoir des plugin avec des classes et des templates.
Une autre question:
Pourquoi je suis obligé de marquer export "C" pour que ca marche ?
J'ai réussi à utiliser appeler une classe d'un plugin avec un template mais c'est de la triche, c'est en utilisant des Wrapper et puis j'etais obligé de fixer un type pour le template.
Moi ce que je veux c'est pouvoir choisir le type du template dans le main et non pas dans le plugin.
Merci
Voici le contenu du plugin:
Alors est ce qu'il y a un moyen de mettre un template a la fonction fct et pouvoir le définir dans le main.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 #include <stdio.h> template< class classTest = int > class Affiche { classTest i; public: Affiche( void ) { i = 14; printf("\\wof wof/\n"); printf(" \\...../\n"); printf(" ...\n"); printf(" .\n"); printf(" <I________/\n" ); printf(" || ||\n"); } // Affiche() int getVal( void ) { return i; } }; extern "C" void* fct( void ) { return new Affiche< int >(); } extern "C" void getVal( void* aff, int &nb ) { nb = (( Affiche< int >* ) aff)->getVal(); }
Contenu du main
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 #include <iostream> #include <dlfcn.h> using namespace std; typedef void* ( * AFFI ) ( void ); typedef void ( * GETVAL ) ( void* aff, int &nb ); int main( void ) { void* dlobj; if( dlobj = dlopen( "test.so", RTLD_LAZY ) ) { // test d'une classe dans une dll AFFI affiche_appel = ( AFFI ) dlsym( dlobj, "fct" ); void* obj = ( * affiche_appel )(); GETVAL getVal_appel = ( GETVAL ) dlsym( dlobj, "getVal" ); int nb = 0; ( * getVal_appel )( obj, nb ); cout << "nb[" << nb << "]\n"; } return 0; } // main()
Ce qu'on se tue à te dire, c'est que c'est NON.
SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.
"Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
Apparently everyone. -- Raymond Chen.
Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.
Partager