Partage
  • Partager sur Facebook
  • Partager sur Twitter

Création d'une extansion (Ipelet) sur IPE

Problème lors d'une création du DLL (Ipelet)

Sujet résolu
    28 mai 2020 à 15:58:42

    Bonjour, 

    Je suis étudiant en deuxième année de DUT info et j'ai actuellement besoin d'aide pour un projet.

    En gros je dois faire une extension du logiciel IPE (http://ipe.otfried.org/) qui est un logiciel en gros de forme Vectoriel, de ce que j'ai compris le logiciel est de base en Lua mais on peut aussi coder en C++ en transformant le code en .dll et en utilisant un Wrapper en Lua. 

    Mon problème c'est lors de la création d'un .dll, je le fais avec MinGW et lors de la compilation de mon code à la compilation du .o en dll (-shared) j'ai cette erreur :

    undefined reference to `ipe::Ipelet::~Ipelet()'

    collect2.exe: erreur: ld a retourn le statut de sortie 1

    l'erreur semble venir de l'include du logiciel mais j'en suis pas sur.

    Je trouve très peu d'aide sur internet sur ce logiciel et j'aimerai bien commencer ce projet.

    Voila mon code de teste

    Mon .h

    #ifdef TESTMYIPELET
    #define MYIPELET __declspec(dllexport)
    #else
    #define MYIPELET __declspec(dllimport)
    #endif
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    class MyIpelet : public ipe::Ipelet {
    public:
      virtual int ipelibVersion() const { return ipe::IPELIB_VERSION; }
      virtual bool run(int function, ipe::IpeletData *data, ipe::IpeletHelper *helper);
    };
    
    #ifdef __cplusplus
    }
    #endif
    

    et mon .cpp

    #include "../include/ipelet.h"
    #include "../include/ipepath.h"
    #include "../include/ipepage.h"
    
    #include "MyIpelet.h"
    
    bool MyIpelet::run(int function, ipe::IpeletData *data, ipe::IpeletHelper *helper)
    {
      helper->message("OUI");
      return true;
    }
    
    IPELET_DECLARE ipe::Ipelet *newIpelet()
    {
      return new MyIpelet;
    }
    

    Je vous donne aussi mes lignes de compilation au cas si je fais des erreurs :

    g++ -c MyIpelet.cpp 

    g++ -shared -o MyIpelet.dll MyIpelet.o

    Je vous remerci par avance :)



    -
    Edité par CorentinMoinard 28 mai 2020 à 17:50:11

    • Partager sur Facebook
    • Partager sur Twitter
      28 mai 2020 à 18:05:13

      Salut ! Déclare le destructeur dans ton ficher en-tête, s'il n'a rien à faire de particulier, tu peux te permettre le déclarer comme étant par défaut (dans ce cas pas besoin de définition pour la fonction).

      #ifdef TESTMYIPELET
      #define MYIPELET __declspec(dllexport)
      #else
      #define MYIPELET __declspec(dllimport)
      #endif
       
      #ifdef __cplusplus
      extern "C" {
      #endif
       
      class MyIpelet : public ipe::Ipelet {
      public:
        virtual int ipelibVersion() const { return ipe::IPELIB_VERSION; }
        virtual bool run(int function, ipe::IpeletData *data, ipe::IpeletHelper *helper);
       
      /** * Dtor par défaut. * Virtuel pour éviter le comportement indéfini si la classe * est utilisée comme une classe de base. */ virtual ~MyIpelet() noexcept = default; }; #ifdef __cplusplus } #endif

      Foutu éditeur !

      Je sais pas si ça fonctionnera, dis moi. En tout cas c'est bizarre car le compilateur est censé fournir un constructeur par défaut si tu ne le fais pas...Donc même si il y avait un appel au destructeur dans un des morceaux de code "squelette" de l'API il ne devrait pas y avoir de problème. Quelqu'un saura certainement d'où ça peut venir.

      -
      Edité par Daimyo_ 28 mai 2020 à 18:30:41

      • Partager sur Facebook
      • Partager sur Twitter
        28 mai 2020 à 18:25:31

        Merci de m'avoir répondu Daimyo :) .

        Alors ça me fais une erreur lors de la compilation 

        C:\Users\coren\Desktop\Projet_Stage\ipe-7.2.18\Extansion>g++ -c MyIpelet.cpp
        Dans le fichier inclus depuis MyIpelet.cpp:5:
        MyIpelet.h:15:12: erreur: utilisation invalide du destructeur ~MyIpelet comme un type
           15 |    virtual ~MyIpelet noexcept = default;

        Je dois avouer que je ne comprend pas l'erreur. 

        • Partager sur Facebook
        • Partager sur Twitter
          28 mai 2020 à 18:30:26

          Les parenthèses... My bad, désolé.

          ...
          virtual ~MyIpelet() noexcept = default;
          ...

          -
          Edité par Daimyo_ 28 mai 2020 à 18:34:37

          • Partager sur Facebook
          • Partager sur Twitter
            28 mai 2020 à 18:39:49

            AAAAAAaaaah c'est moi déso je suis fatigué (j'ai recopier comme un débile) alors j'ai toujours la même erreur du coup qu'avant.

            C:\Users\coren\Desktop\Projet_Stage\ipe-7.2.18\Extansion>g++ -c MyIpelet.cpp
            
            C:\Users\coren\Desktop\Projet_Stage\ipe-7.2.18\Extansion>g++ -shared -o MyIpelet.dll MyIpelet.o
            c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: MyIpelet.o:MyIpelet.cpp:(.text$_ZN8MyIpeletD1Ev[__ZN8MyIpeletD1Ev]+0x19): undefined reference to `ipe::Ipelet::~Ipelet()'
            collect2.exe: erreur: ld a retourn le statut de sortie 1



            • Partager sur Facebook
            • Partager sur Twitter
              28 mai 2020 à 18:56:42

              Je comprends pas, pourtant tu n'appelles pas du tout ton destructeur... Essaie de définir un corps à la fonction (il faut donc enlever le default):

              // #####=======--------- Fichier.hpp ---------=======#####
              virtual ~MyIpelet() noexcept;
              // noexcept seulement si tu es certain de ne pas lever d'exception dans
              // le corps de la fonction !
              
              // #####=======--------- Fichier.cpp ---------=======#####
              MyIpelet::~MyIpelet() noexcept {
                // ...
              }
              

              // Toujours programmer avec style !

              -
              Edité par Daimyo_ 28 mai 2020 à 18:58:40

              • Partager sur Facebook
              • Partager sur Twitter
                28 mai 2020 à 18:58:48

                J'ai déjà essayer et j'ai toujours la même erreur 

                • Partager sur Facebook
                • Partager sur Twitter
                  28 mai 2020 à 19:12:25

                  C'est une erreur d'édition de lien, pas de compilation.

                  Le problème est dans la configuration du projet/options dans les lignes de commande.

                  Vous devez ajouter à vos lignes de commande le nom et le chemin vers le fichier ".a" contenant l'implémentation de la classe "Ipelet".

                  Compulsez la documentation de MinGW pour savoir comment spécifier le nom et le chemin vers des librairies.

                  (En espérant que ce machin donne ce type de fichier, ou que vous soyez en mesure de les générer cf. leur documentation)

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                    28 mai 2020 à 19:14:08

                    Ah je viens seulement de remarquer que le destructeur qui pose problème n'est pas celui de MyIpelet, mais celui de la classe de l'API... Je pense que c'est une erreur d'édition des liens due au fait que tu n'aies pas lié la bibliothèque qui implémente le destructeur de la classe ip::Ipelet.

                    Tu as inclus le fichier qui donne la déclaration de la classe, mais pas le corps des fonctions. Il faut que tu trouves la bibliothèque qu'il manque et qui tu l'ajoutes dans tes options de compilation ainsi:

                    g++ objet.o -o executable -L/chemin/vers/lib/ -lnomlib

                     Je vois que je suis en retard...

                    -
                    Edité par Daimyo_ 28 mai 2020 à 19:15:14

                    • Partager sur Facebook
                    • Partager sur Twitter
                      28 mai 2020 à 20:18:58

                      Salut,

                      Daimyo_ a écrit:

                      Je comprends pas, pourtant tu n'appelles pas du tout ton destructeur... Essaie de définir un corps à la fonction (il faut donc enlever le default):

                      Ben si... Bien sur que tu appelles le destructeur de ta classe. Dés le moment où tu crées une instance de classe, un constructeur est appelé au moment de la création de l'instance, et le destructeur est appelé au moment où l'instance est détruite, et ce, de manière strictement automatique.

                      On dispose même d'une règle indiquant explicitement ce qui est fait et dans quel ordre, aussi bien pour le constructeur que pour le destructeur.  A savoir que la destruction se fera exactement dans l'ordre inverse de la construction ;)

                      Ainsi, lorsque tu crées une instance d'une classe dérivée, la construction va se faire dans l'ordre suivant:

                      • appel du constructeur adéquat pour la classe mère
                      • construction des données membres non statiques pour lesquelles on ne fait pas appel à l'allocation dynamique de la mémoire (s'il y en a)
                      • instructions données par le constructeur (s'il y en a)

                      Et la destruction de l'instance de cette classe se fera dans l'ordre suivant:

                      • instruction données par le destructeur (s'il y en a)
                      • destruction des données membre non statiques pour lesquelles on en fait pas appel à  l'allocaiton dynamique de la mémoire (s'il y en a)
                      • appel du destructeur de la classe mère

                      Le problème, ici est "simplement" un problème d'édition de liens "classique", dans le sens où l'éditeur de liens se plaint du fait qu'il ne trouve pas le code binaire exécutable correspondant au destructeur de la classe parent (Ipe::Ipelet) lorsqu'il doit effectuer la liaison avec le destructeur de la classe dérivée (MyIpelet).

                      La raison du problème est donc toute simple : l'éditeur de liens ne sais pas, au moment de créer la dll, qu'il doit aller voir dans la bibliothèque (la dll) qui fournit les fonctionnalités de ipe.

                      La solution est tout aussi simple: il "suffit" normalement, de rajouter l'option -lipe (attention, c'est un L minutscule) et peut être l'option -L<chemin d'accès vers ipe.dmm> ) au moment de générer la dll, sous une forme qui sera donc proche de

                      g++ -shared -o MyIpelet.dll MyIpelet.o -lipe.dll

                      (il faut aussi faire attention au fait d'utiliser le même compilateur, dans sa même version que celui utilisé par le projet ipe, car la compatibilité n'est pas forcément certiane)

                      • Partager sur Facebook
                      • Partager sur Twitter
                      Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                        28 mai 2020 à 20:33:39

                        Oui @koala. Merci pour ces infos, ça fait pas de mal d'apprendre des choses de ce genre.

                        En fait j'ai été trop vite dans l'analyse du problème, je n'avais simplement pas remarqué qu'il s'agissait du destructeur de la classe de base et non pas de la classe créée par l'utilisateur... Et oui, tu as raison, le destructeur est toujours appelé, quelque soit le contexte ! Mais encore une fois, je me suis mal exprimé, je voulais dire "appelé explicitement", dans le sens ou l'utilisateur fait un appel au le destructeur, lui même. Mais quelque soit ma parole, il y avait une incohérence dans mes propos, car avant d'y avoir une erreur d'édition des liens, il aurait du y avoir une erreur de compilation qui dit que le destructeur n'est pas déclaré.

                        Bref... désolé pour ma précipitation et le fait que mon intervention ait été brouillon.

                        • Partager sur Facebook
                        • Partager sur Twitter
                          29 mai 2020 à 11:51:51

                          Alors quand j'ai essayer de compiler il ne me trouve pas l'option -lipe (c'est -lipe pas -lipe.dll ? (j'ai essayer les deux de toute façon)) .

                          C:\Users\coren\Desktop\Projet_Stage\ipe-7.2.18\Extansion>g++ -shared -o MyIpelet.dll MyIpelet.o -lipe.dll
                          c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: cannot find -lipe.dll
                          collect2.exe: erreur: ld a retourn le statut de sortie 1
                          
                          C:\Users\coren\Desktop\Projet_Stage\ipe-7.2.18\Extansion>g++ -shared -o MyIpelet.dll MyIpelet.o -lipe
                          c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: cannot find -lipe
                          collect2.exe: erreur: ld a retourn le statut de sortie 1

                          Alors normalement j'ai pas besoin normalement de rajouter l'option -L car j'ai ajouter à mon PATH le chemin au bin du projet.

                          Ce serait du à la diférence de compilateur ? j'ai regardé et la version du compilateur utilisé pour compiler IPE est g++-mingw-w64-x86-64 et le mien c'est x86_64-w64-mingw32-g++. Je ne pense pas que les deux versions soit si différentes ?



                          • Partager sur Facebook
                          • Partager sur Twitter
                            29 mai 2020 à 12:54:42

                            Avec GCC ça a toujours été les mêmes options de compilation. Précisément, tu as ajouté quel chemin à ton PATH, et pourquoi ? Essaie quand même d'ajouter le chemin qui mène vers la bibliothèque, on ne sait jamais. Et tu es certain qu'elle s'appelle ipe ?
                            • Partager sur Facebook
                            • Partager sur Twitter
                              29 mai 2020 à 15:00:33

                              J'ai rajouter dans mon PATH le chemin des dll du logiciel, genre le "bin" c'est pour pouvoir lancer le .exe directement depuis mon cmd mais sinon il me semble bien que ça indique l'emplacement des dll (comme quand tu le défini avec MingW).

                              Sinon il y a bien ipe.dll et aussi j'ai essayer la compilation en lui indiquant le chemin.

                              C:\Users\coren\Desktop\Projet_Stage\ipe-7.2.18\Extansion>g++ -shared -o MyIpelet.dll MyIpelet.o -L C:\Users\coren\Desktop\Projet_Stage\ipe-7.2.18\bin -l ipe.dll
                              c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: cannot find -lipe.dll
                              collect2.exe: erreur: ld a retourn le statut de sortie 1
                              • Partager sur Facebook
                              • Partager sur Twitter
                                30 mai 2020 à 12:59:18

                                Bon, je me suis un peu penché sur le problème, et voici la solution que j'ai trouvée:

                                Il faut travailler en trois temps:

                                Dans un premier temps, il faudra écrire le code de ton ipelet

                                Il faut faire attention au fait que tu as au minimum deux fonctions virtuelles pures dans la classe ipe::Ipelet: les fonctions

                                int ipelibVersion() const

                                et

                                 bool run(int function, ipe::IpeletData *data, ipe::IpeletHelper *helper)

                                Ton ipelet devrait donc ressembler à quelque chose comme

                                (pour le fichier d'en-tête)

                                #pragma once
                                #include <ipelet.h>
                                
                                class  MyIpelet : public ipe::Ipelet{
                                public:
                                    MyIpelet() = default;
                                    ~MyIpelet() = default;
                                    int ipelibVersion() const final override;
                                    bool run(int function, ipe::IpeletData *data, ipe::IpeletHelper *helper) final override;
                                };

                                (pour le fichier d'implémentation)

                                #include <MyIpelet.hpp>
                                int MyIpelet::ipelibVersion() const {
                                    return 1;
                                }
                                
                                bool MyIpelet::run(int function, ipe::IpeletData *data, ipe::IpeletHelper *helper){
                                    // ce qu'il faut faire, en utilisant helper et en lui transmettant data
                                    return true;
                                }

                                Evidemment, cela signifie que tu devra aussi faire dériver au moins une classe personnalisée de ipe::IpeletHelper (chose que je n'ai pas faite ici).

                                Une fois le code correctement mis au point, il faudra commencer par générer le fichier objet exécutable (pas la dll dans l'immédiat) en utilisant la commande

                                >g++ -c MyIpelet.cpp -I. -I<chemin\vers\dossier\include_de_ipe>

                                Où l'option -I. permettra au compilateur de trouver le fichier d'en-tête de ton ipelet et où l'option -I<chemin\vers\dossier\include_de_ipe> (tu dois donner le chemin correct ;) ) permettra de trouver le fichier ipe.h

                                Une fois le fichier objet généré, tu pourras l'utiliser pour créer la dll qui servira d'ipelet.

                                "En temps normal" (comprend: si notre dll était destinée à être appelée par une application que nous voulions créer nous même, et non à être utilisée comme plugin dans une application existante), nous aurions pu utiliser une ligne de commande proche de

                                g++ -shared -o myipelet.dll MyIpelet.o <chemin\vers\>ipe.dll -Wl,--out-implib,libmyipelet_dll.a

                                (note que l'on indique clairement à l'éditeur de liens qu'il doit faire le lien avec ipe.dll.  Pour cela, il faut fournir le chemin qui lui permettra d'y accéder ;) )

                                qui nous aurait généré, en plus de la dll en elle-même, une bibliothèque d'importation libmyipelet_dll.a et qui nous aurait permis, par la suite, de générer notre application avec une commande proche de

                                g++ main.cpp -I. -I <chemin\vers\>ipe.dll -lmyipelet_dll  -L.

                                Evidemment, comme tu ne vas pas créer ta propre application (vu que tu veux créer un plugin pour l'application existante), la commande peut être simplifiée pour prendre la forme de

                                g++ -shared -o myipelet.dll MyIpelet.o <chemin\vers\>ipe.dll

                                Au final, "tout ce que tu as à faie", hormis le fait de ne pas essayer de tout faire en une fois, c'est d'ajouter le fait que tu veux utiliser ipe.dll comme source (en fournissant le chemin permettant à accéder à la dll) à chaque fois que tu utilise l'option -shared.

                                Une fois ta dll générée, il faudra sans doute la copier dans le dossier ipelet de ipe ;)

                                • Partager sur Facebook
                                • Partager sur Twitter
                                Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                  1 juin 2020 à 10:19:38

                                  Salut tout le monde j'ai enfin réussi à créer cette dll (Victory !!!).

                                  Alors je vais quand même expliquer pourquoi en fait j'ai eu beaucoup de mal pour réussir.

                                  En fait j'avais bien une différence de compilateur et du coup lorsque j'essayer de créer ma dll, j'avais une erreur de reconnaissance de forma de ipe.dll donc c'est pour ça qu'il ne le trouver pas car je n'utilisais pas le même compilateur avec lequel été compilé le projet IPE de base.

                                  J'ai donc utilisé la dernière version de Mingw (à se lien https://sourceforge.net/projects/mingw-w64/) et du coup j'ai pu créer ma dll.

                                  Donc je peux clore le problème :)

                                  MERCI ENCORE A TOUS

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Création d'une extansion (Ipelet) sur IPE

                                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                  • Editeur
                                  • Markdown