Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1750 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  librairie dynamique et instanciation

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

librairie dynamique et instanciation

n°2049400
codablank
Posté le 16-01-2011 à 00:34:12  profilanswer
 

Bonsoir, après avoir lu le tutorial http://hiko-seijuro.developpez.com/a...que-dynamique/ sur la création de librairie dynamique en c++ sous linux et testé son exemple, je m'interroge sur la manière d'instancier un objet dans le code de la librairie
 
mettons la classe "circle" (issue du tuto):
 

Code :
  1. circle.h
  2. #ifndef CIRCLE_H_
  3. #define CIRCLE_H_
  4. #include <iostream>
  5. #include test.h
  6. class circle
  7. {
  8. public:
  9.     virtual void draw();
  10. };
  11. typedef circle *(*maker_circle)();
  12. #endif
  13. circle.cpp
  14. #include "circle.h"
  15. using namespace std;
  16. void circle::draw()
  17. {
  18.     cout << "   ###   " << endl;
  19.     cout << "  #   #  " << endl;
  20.     cout << " #     # " << endl;
  21.     cout << " #     # " << endl;
  22.     cout << "  #   #  " << endl;
  23.     cout << "   ###   " << endl;
  24. }
  25. extern "C"
  26. {
  27.     circle *make_circle()
  28.     {
  29.  return new circle();
  30.     }
  31. }


 
j'ai voulu ajouter une autre classe "test" :
 

Code :
  1. test.h
  2. #ifndef TEST_H_
  3. #define TEST_H_
  4. #include <iostream>
  5. class test
  6. {
  7. public:
  8.    
  9. Test();
  10. ~Test();
  11.    void print();
  12. };
  13. #endif
  14. test.cpp
  15. #include "test.h"
  16. using namespace std;
  17. Test::Test(){}
  18. Test::~Test(){}
  19. void Test::print(){
  20.     cout << "   TEST  " << endl;
  21. }


 
j'ai voulu l'instancier dans la méthode "draw" de "circle" :
 

Code :
  1. void circle::draw()
  2. {
  3.     cout << "   ###   " << endl;
  4.     cout << "  #   #  " << endl;
  5.     cout << " #     # " << endl;
  6.     cout << " #     # " << endl;
  7.     cout << "  #   #  " << endl;
  8.     cout << "   ###   " << endl;
  9.     Test* test = new Test();
  10.     test->print();
  11. }


 
voici le main.cpp:
 

Code :
  1. #include "circle.h"
  2. #include "test.h"
  3. #include <cstdlib>
  4. #include <iostream>
  5. #include <dlfcn.h>
  6. using namespace std;
  7. int main(int argc, char **argv)
  8. {
  9.     void *hndl;
  10.     maker_circle pMaker;
  11.     // Ouverture de la librairie
  12.     hndl = dlopen("./libcircle.so", RTLD_LAZY);
  13.     if(hndl == NULL)    {
  14.  cerr << "dlopen : " << dlerror() << endl;
  15.  exit(EXIT_FAILURE);
  16.     }
  17.     // Chargement du créateur
  18.     void *mkr = dlsym(hndl, "make_circle" );
  19.     if (mkr == NULL)
  20.     {
  21.  cerr << "dlsym : " << dlerror() << endl;
  22.  exit(EXIT_FAILURE);
  23.     }
  24.     pMaker = (maker_circle)mkr;
  25.     // Création, affichage puis destruction du cercle
  26.     circle *my_circle = pMaker();
  27.     my_circle->draw();
  28.     dlclose(hndl);
  29.     return EXIT_SUCCESS;
  30. }


 
je compile en librairie dynamique sans problème avec :
 

Code :
  1. libcircle.so: circle.cpp circle.h test.h test.cpp
  2. g++  -shared -o libcircle.so circle.cpp
  3. example: main.cpp libcircle.so
  4. g++  -o example main.cpp -ldl


 
mais à l'exécution, j'obtiens un "undefined symbol: _ZN4TestC1Ev"
 
ai-je mal instancié ?  :(  
 
si je retire  
 

Code :
  1. Test* test = new Test();
  2.     test->print();


 
ça marche nickel et j'ai le résultat attendu

mood
Publicité
Posté le 16-01-2011 à 00:34:12  profilanswer
 

n°2049404
xilebo
noone
Posté le 16-01-2011 à 07:59:48  profilanswer
 

il te manque un -lcircle pour que ton exécutable soit linké avec libcircle. Même pour un link sur une bibliothèque dynamique, il faut ce genre de chose.
 
 

Code :
  1. g++  -o example main.cpp -ldl -lcircle


 
 
 
Il faut également avoir précisé le chemin de la bibliothèque avec -L si celle ci ne se trouve pas dans un chemin connu de g++.
 
 

Code :
  1. g++  -o example main.cpp -ldl -lcircle -L/path/to/library

Message cité 1 fois
Message édité par xilebo le 16-01-2011 à 08:02:49
n°2049408
Un Program​meur
Posté le 16-01-2011 à 08:46:11  profilanswer
 

codablank a écrit :


mais à l'exécution, j'obtiens un "undefined symbol: _ZN4TestC1Ev"


 
Pour qu'une lib chargée avec dlopen puisse utiliser des symboles du programme principal, il y a des choses à faire (et je ne les retiens pas d'une fois sur l'autre).  Regarde les différentes options de gcc, ça me suffit généralement pour retrouver ce qu'il faut.
 

xilebo a écrit :

il te manque un -lcircle pour que ton exécutable soit linké avec libcircle.


 
Il utilise dlopen()...


---------------
The truth is rarely pure and never simple (Oscar Wilde)
n°2049411
xilebo
noone
Posté le 16-01-2011 à 09:08:05  profilanswer
 

Un Programmeur a écrit :


 
Pour qu'une lib chargée avec dlopen puisse utiliser des symboles du programme principal, il y a des choses à faire (et je ne les retiens pas d'une fois sur l'autre).  Regarde les différentes options de gcc, ça me suffit généralement pour retrouver ce qu'il faut.
 


 

Un Programmeur a écrit :


 
Il utilise dlopen()...


 
 
Désolé, je n'avais pas fait gaffe  :jap:

n°2049440
gilou
Modérateur
Modzilla
Posté le 16-01-2011 à 12:51:06  profilanswer
 

Citation :

g++  -shared -o libcircle.so circle.cpp


Et avec:
g++ -fPIC -shared -o libcircle.so circle.cpp test.cpp
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2049453
Un Program​meur
Posté le 16-01-2011 à 13:57:50  profilanswer
 

C'est vraisemblablement la solution.  J'avais vu qu'il ne mettais pas test.cpp dans libcircle.so et j'avais supposé sans vérifié qu'il le mettais avec main.cpp (ce qui a posteriori est doublement stupide considérant les dépendances déclarées pour libcircle.so).


---------------
The truth is rarely pure and never simple (Oscar Wilde)
n°2049471
gilou
Modérateur
Modzilla
Posté le 16-01-2011 à 15:31:54  profilanswer
 

Codablank, si j'avais eu a écrire ce code, j'aurais plus ou moins fait comme suit:

Code :
  1. /////////////////////////////////////////////////////////////////////////////
  2. // circle.h
  3. #ifndef CIRCLE_H_
  4. #define CIRCLE_H_ 
  5. #include "test.h"  // à commenter si l'on veut tester sans la classe test
  6. class Circle {
  7. #ifdef TEST_H_
  8.   friend class Test;
  9. #endif
  10.   public: virtual void draw();
  11. };
  12. #endif
  13. /////////////////////////////////////////////////////////////////////////////
  14. //test.h
  15. #ifndef TEST_H_
  16. #define TEST_H_
  17. class Test {
  18.   void print();
  19. };
  20. #endif
  21. /////////////////////////////////////////////////////////////////////////////
  22. // circle.cpp
  23. #include "circle.h"
  24. #include <iostream>
  25. using std::cout;
  26. extern "C" Circle* create() {
  27.   return new Circle;
  28. }
  29. extern "C" void destroy(Circle* c) {
  30.   delete c;
  31. }
  32. void Circle::draw()
  33. {
  34.     cout << "   ###   " << endl;
  35.     cout << "  #   #  " << endl;
  36.     cout << " #     # " << endl;
  37.     cout << " #     # " << endl;
  38.     cout << "  #   #  " << endl;
  39.     cout << "   ###   " << endl;
  40. #ifdef TEST_H_
  41.     Test* test = new Test;
  42.     test->print();
  43.     delete test;
  44. #endif
  45. }
  46. /////////////////////////////////////////////////////////////////////////////
  47. // test.cpp
  48. #include <iostream>
  49. #include "test.h"
  50. using std::cout;
  51. void Test::print() {
  52.     cout << "   TEST  " << endl;
  53. }
  54. /////////////////////////////////////////////////////////////////////////////
  55. // main.cpp
  56. #include <cstdlib>
  57. #include <iostream>
  58. #include <dlfcn.h>
  59. #include "circle.h"
  60. using namespace std;
  61. int main(int argc, char **argv) {
  62.   int exit_code = EXIT_SUCCESS;
  63.   void *hndl = dlopen("./libcircle.so", RTLD_LAZY); // Ouverture de la librairie
  64.  
  65.   if (hndl == NULL) {
  66.     cerr << "dlopen : " << dlerror() << endl;
  67.     exit_code = EXIT_FAILURE;
  68.   }
  69.   else {
  70.     Circle* (*create_circle)();
  71.     void (*destroy_circle)(Circle*);
  72.    
  73.     create_circle = (Circle* (*)()) dlsym(hndl, "create" );
  74.     destroy_circle = (void (*)(Circle*)) dlsym(hndl, "destroy" );
  75.     if (create_circle == NULL || destroy_circle == NULL) {
  76.       cerr << "dlsym : " << dlerror() << endl;
  77.       exit_code = EXIT_FAILURE;
  78.     }
  79.     else {
  80.       Circle* my_circle = create_circle();
  81.       my_circle->draw();
  82.       destroy_circle(my_circle);
  83.     }
  84.     dlclose(hndl);
  85.   }
  86.   return exit_code;
  87. }
  88. /////////////////////////////////////////////////////////////////////////////


(Bon, j'ai pas de compilo sous la main, donc pas testé)
Il y a pas de grosses diffs, mais l'emploi des directives préprocesseur permet de n'avoir qu'un endroit à commenter pour utiliser test ou non
Et plutôt que d'avoir un constructeur et un destructeur publics sans paramètres, l'emploi d'une classe friend me parait mieux coller.
Par contre, le déport de
#include <iostream>
dans cercle.h au lieu de cercle.cpp alors que rien dans cercle.h n'utilise iostream, je suis tout à fait contre.
Et dans le même genre de remarque, il n'y a aucune raison de faire figurer test.h dans main.cpp vu qu'on ne fait pas appel à Test dans son code.

 

A+,


Message édité par gilou le 16-01-2011 à 15:55:58

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2049473
gilou
Modérateur
Modzilla
Posté le 16-01-2011 à 15:38:11  profilanswer
 

Un dernier point:

Code :
  1. class test
  2. {
  3. public:
  4.  
  5. Test();
  6. ~Test();
  7.    void print();
  8. };


Si le nom de ta classe est test, et non pas Test, il va y avoir des problèmes...
Dans le même genre, nommer une classe circle sans majuscule, pourquoi pas, mais utiliser une convention de nommage de base, ça peut faciliter le repérage des erreurs.

 

A+,


Message édité par gilou le 16-01-2011 à 15:39:26

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2049478
codablank
Posté le 16-01-2011 à 15:57:44  profilanswer
 

Merci pour toutes vos  réponses  [:dawa]  
 
effectivement j'avais omis test.cpp dans la compilation de la librairie, donc binaire de Test impossible à trouver pour le main
 
gilou, merci pour tes corrections, c'était à la base juste un code de test, mais tes conseils vont me permettre de bâtir un chargeur de .so un peu plus propre
 
à propos existe-il une api standard pour ce genre de chose en C++ ?

n°2049479
gilou
Modérateur
Modzilla
Posté le 16-01-2011 à 16:00:22  profilanswer
 

Citation :

à propos existe-il une api standard pour ce genre de chose en C++

Non, ça dépend de l'OS, les librairies partagées/dlls.
Sous unix, selon les unix, ça a toujours été le bordel au niveau des options pour le compilo, les librairies partagées (AIX / SunOS ou Solaris par exemple).
A+,


Message édité par gilou le 16-01-2011 à 16:11:08

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  librairie dynamique et instanciation

 

Sujets relatifs
Navigation dynamique en JQueryProbleme allocation dynamique
Tableaux croisé dynamiqueLibrairie pour décoder le langage texto
page dynamique affichant l'arborescence d'un répGlade - duo Gtk XML et intégration dynamique de composant.
Structure + Tableau dynamique en langage C[resolu]allocation dynamique double pointeur passer en parametre
Instanciation d'un Object + Compatibilité MacOS[C] tableau dynamique 2 dimension
Plus de sujets relatifs à : librairie dynamique et instanciation


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR