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.
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).
/**
* 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.
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 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 {
// ...
}
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:
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)
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
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.
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 ?
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 ?
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
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
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
(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
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
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
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
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.
× 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.
https://zestedesavoir.com/tutoriels/822/la-programmation-en-c-moderne/
https://zestedesavoir.com/tutoriels/822/la-programmation-en-c-moderne/
https://zestedesavoir.com/tutoriels/822/la-programmation-en-c-moderne/
https://zestedesavoir.com/tutoriels/822/la-programmation-en-c-moderne/
https://zestedesavoir.com/tutoriels/822/la-programmation-en-c-moderne/
https://zestedesavoir.com/tutoriels/822/la-programmation-en-c-moderne/