IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Librairie static incluse dans librairie dynamique


Sujet :

C++

  1. #1
    Membre habitué
    Inscrit en
    Juin 2003
    Messages
    223
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Juin 2003
    Messages : 223
    Points : 145
    Points
    145
    Par défaut Librairie static incluse dans librairie dynamique
    Bonjour,

    J'ai créer une librairie qui utilise les librairie tinyxml et libjpeg.
    Ayant seulement envie d'intégrer et de distribué ma librairie j'ai decidé de faire la chose suivant:

    Je compile tinyxml en static
    Je compile libjpeg en static

    Puis je compile malib en dynamic en incluant les versions deux autres librairies:

    Sous MinGW les commandes pour linker donnent:

    C:\MinGW\bin\ar.exe cr ..\lib\libtinyxml.a tinystr.cpp.obj tinyxml.cpp.obj \tinyxmlerror.cpp.obj tinyxmlparser.cpp.obj
    C:\MinGW\bin\ranlib.exe ..\lib\libtinyxml.a

    meme chose pour jpeg

    C:\MinGW\bin\gcc.exe -shared -o bin\malib.dll -Wl,--out-implib,lib\malib.dll.a -Wl,--major-image-version,1,--minor-image-version,0 obj1.o obj2.o obj3.o 3rdparty\lib\liblibjpeg.a 3rdparty\lib\libtinyxml.a

    Au final quand je créer mon programme je doit utiliser:

    C:\MinGW\bin\g++.exe -Wall main.cpp.obj -o bin\AdVisOr.exe -Wl,--out-implib,lib\libAdVisOr.dll.a -Wl,--major-image-version,0,--minor-image-version,0 lib\malib.dll.a 3rdparty\lib\liblibjpeg.a 3rdparty\lib\libtinyxml.a

    alors que j'aimerais ne pas avoir a inclure 3rdparty\lib\liblibjpeg.a 3rdparty\lib\libtinyxml.a, car du coup cela me désavantage de devoir inclure de nouveaux les librairies static.

    Je ne trouve pas grand chose sur le Web et j'utilise Cmake pour la compilation.

  2. #2
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Tout simplement parce que tu as exporté des éléments de tes deux librairies statiques dans l'interface de ta librairie dynamique... Du coup, un programme utilisant la DLL doit linker aussi avec les librairies statiques pour réussir à trouver tous les symboles.

    Typiquement, c'est mettre dans un entête de classe un attribut qui est défini dans une librairie statique (=> demande à faire une classe intermédiaire et/ou du cast sauvage avec void*) et/ou du code (toujours dans le .H) utilisant directement les fonctions de la librairie statique (=> les mettre dans le .CPP).

    Tu as aussi la farce quand ton compilateur exporte par défaut TOUTES les fonctions de la DLL, au lieu de se limiter à celles définies explicitement. Là, faut voir la doc du compilo pour savoir comment empêcher l'exportation d'un symbole dans une DLL.

    Il te faut :
    • Vérifier ce que ta DLL exporte actuellement (via Dependancy Walker), afin de repérer l'élément posant problème.
    • Repenser ton interface DLL de façon à n'exposer QUE tes propres fonctions / classes, en MASQUANT l'implémentation / utilisation des éléments des deux librairies statiques.
      Ceci implique un remaniement lourd de tes entêtes, l'utilisation de classes plus génériques qui seront les seules réellement exportées, l'utilisation de "void*" à outrance avec casts internes pour masquer le type réel de l'implémentation, ...
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  3. #3
    Membre habitué
    Inscrit en
    Juin 2003
    Messages
    223
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Juin 2003
    Messages : 223
    Points : 145
    Points
    145
    Par défaut
    Oky, merci

    donc si j'utilise des fonctions de tinyxml dans ma libraires et dans mon programmes j'ai intérêt a l'utiliser en tant que shared, ou directement inclure le code dans malib.dll.

    Par contre si j'arrive a cacher libjpeg c'est mieux de le compiler en statique et de le cacher dans malib.

    c'est bien ca ?

  4. #4
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Je vais prendre un exemple, ce sera plus clair...

    Voici par exemple un bout du code d'une librairie statique :
    Code Private.h : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include <........>
     
    // Structure de contrôle utilisée partout dans la librairie pour toutes les fonctions, comme l'est "FILE*" pour l'accès aux fichiers.
    typedef struct {
     ....
     ....
     ....
    } private_handle ;
    Ce code est censé, à priori, rester "planqué" et non visible depuis ta DLL.

    Or, imaginons que tu as un entête public de ta DLL construit ainsi :
    Code Public.h : 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
    #include "Private.h" // pour "private_handle"
    
    class Bidule {
    
      // Ouverture d'une ressource. La valeur de retour est passé à toutes les méthodes de la classe, MAIS L'UTILISATEUR NE LA MANIPULE JAMAIS DIRECTEMENT.
      // La méthode met à jour l'attribut m_PrivateHandle de la classe.
      bool Open ( .... ) ;
    
      // Travail effectif.
      int Process ( ..... ) ;
    
      // Fermeture.
      bool Close ( void ) ;
    
    private:
      private_handle* m_PrivateHandle ;
    
    } ;

    Problème : private_handle fait partie de la librairie statique, devrait être privé, et est utilisé par une classe publique via un attribut... Du coup, pour pouvoir compiler, tu dois inclure l'entête de la librairie statique, qui va bien entendu forcer un link de cette librairie statique au sein de ton exécutable, alors que tu croyais n'utiliser que ta DLL !!

    Pour corriger, tu devras faire ainsi :
    Code Public.h : 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
    // On supprime le #include public vers la librairie statique.
    
    class Bidule {
    
      // Ouverture d'une ressource. La valeur de retour est passé à toutes les méthodes de la classe, MAIS L'UTILISATEUR NE LA MANIPULE JAMAIS DIRECTEMENT.
      // La méthode met à jour l'attribut m_PrivateHandle de la classe.
      bool Open ( .... ) ;
    
      // Travail effectif.
      int Process ( ..... ) ;
    
      // Fermeture.
      bool Close ( void ) ;
    
    private:
      void* m_MaskedPrivateHandle ;  // Passage en void*
    
    } ;
    Code Public.cpp : 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
    #include "Public.h"
    #include "Private.h" // pour "private_handle", il passe donc dans le CPP.
     
    bool Bidule::Open ( .... ) {
     
      private_handle* m_PrivateHandle ;
     
      // Reste de la fonction.
     
      // Affectation de l'attribut avec cast.
      m_MaskedPrivateHandle = static_cast<void*>(m_PrivateHandle) ;
    }
     
    int Bidule::Process ( ..... ) {
     
      // Via un cast, on récupère le handle "normalement", avec l'ancien nom d'attribut pour éviter d'avoir à modifier inutilement le code déjà écrit.
      private_handle* m_PrivateHandle = static_cast<private_handle*>(m_MaskedPrivateHandle) ;
     
      // Corps de la fonction, inchangé désormais.
    }
     
    ...
    Ainsi, même si la DLL continue d'utiliser la librairie statique, cela n'est pas visible de l'extérieur, et aucun entête de la librairie statique n'est requis. Du coup, ton exécutable n'aura plus besoin d'être linké avec la librairie statique en question...


    Tu vois mieux de quoi je veux parler ?
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  5. #5
    Membre habitué
    Inscrit en
    Juin 2003
    Messages
    223
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Juin 2003
    Messages : 223
    Points : 145
    Points
    145
    Par défaut
    Oky, parfait ...
    merci pour l'aide

  6. #6
    Expert éminent

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Je pense que Mac y va un peu fort....

    Si ton entete est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    struct mallibprivatestruct;
    class DLL_EXPORT DeMaLib
    {
        private:
          malibprivatestruct*   m_pStruct;
    };
    Personne (utilisateur) n'a besoin d'avoir la définition de malibprivatestruct, juste celle d'un pointeur !
    N'oubliez pas de cliquer sur mais aussi sur si un commentaire vous a été utile !
    Et surtout

  7. #7
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par nicroman Voir le message
    Personne (utilisateur) n'a besoin d'avoir la définition de malibprivatestruct, juste celle d'un pointeur !
    Et en utilisant ta DLL via cette interface, ton exécutable va gueuler comme quoi tu as une déclaration forward non résolue...
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  8. #8
    Membre habitué
    Inscrit en
    Juin 2003
    Messages
    223
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Juin 2003
    Messages : 223
    Points : 145
    Points
    145
    Par défaut
    Ouais exactement, je faisait ça avant et avait des problèmes avec ce genre de manip!

    il me reste encore un petit problème avec le compilateur MVC et ce bout de code.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class X7sParamList {
    private:
    std::map<int,X7sParam*> m_mapID;
    }
    Et la le void* ne me fonctionne pas

  9. #9
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par elraton Voir le message
    Et la le void* ne me fonctionne pas
    Ben si, mais c'est dans tout ce qui va utiliser ton X7sParamList qu'il faudra faire les casts. Mais tu peux sans problème modifier ton X7sParam* en void*, toutefois l'appel / utilisation de X7sParamList risque d'être un peu lourdingue.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  10. #10
    Membre habitué
    Inscrit en
    Juin 2003
    Messages
    223
    Détails du profil
    Informations personnelles :
    Âge : 39

    Informations forums :
    Inscription : Juin 2003
    Messages : 223
    Points : 145
    Points
    145
    Par défaut
    nan en fait c'est le std::map<> qui me donne des erreurs car il s'agit d'un templates, et les templates dans les libraries ca donne tout plein de warning

  11. #11
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par Mac LAK Voir le message
    Et en utilisant ta DLL via cette interface, ton exécutable va gueuler comme quoi tu as une déclaration forward non résolue...
    J'ai du mal à comprendre ça... Pourrais-je avoir un exemple?
    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.

  12. #12
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    J'ai du mal à comprendre ça... Pourrais-je avoir un exemple?
    Sous Visual, c'est une erreur C2079 ("'variable' utilise une struct de 'machin' non défini") qui peut être levée. Le code montré par nicroman fonctionnera souvent, principalement dans les cas simples, mais aura de gros soucis dans certains cas d'utilisation plus complexes où le type "malibprivatestruct*" sera déréférencé et/ou indexé (ex : utilisation d'un "malibprivatestruct[20]" à la place d'un "malibprivatestruct*"), ce qui est toujours possible si l'attribut est public (ou même en protected, via héritage).

    Le problème étant que l'erreur est alors plutôt cryptique, voire difficile à trouver, tandis qu'un masquage intégral par "void*" n'occasionne jamais ce genre de soucis (on a alors, toujours sous VC++, une erreur C2182 ("utilisation non conforme du type 'void'"), ce qui est nettement plus clair étant donné que le type est clairement marqué comme "void*").

    La manière "bourrine" de lever cette erreur est d'inclure les entêtes de la librairie statique que l'on voulait justement masquer, et de linker avec : la C2079 est alors levée, mais on garde la dépendance avec la librairie statique que l'on voulait justement ne plus avoir au niveau de l'exécutable. L'utilisation d'un void* explicite, par contre, masque intégralement la librairie statique dans l'interface publique de la DLL, quoi qu'il arrive.

    Cela permet aussi, si besoin, de faire un masquage en C (non C++, donc) même sur des compilateurs anciens et/ou exotiques.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    D'un autre côté, pour moi, tenter de déréférencer un malibprivatestruct*, c'est comme vouloir déréférencer un FILE* :
    "Y'en a qu'ont essayé, ils ont eu des problèmes. Et c'est leur faute."
    J'aime que mes pointeurs opaques soient typés, ça évite de les confondre.
    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.

  14. #14
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    D'un autre côté, pour moi, tenter de déréférencer un malibprivatestruct*, c'est comme vouloir déréférencer un FILE*
    Le but étant d'avoir une DLL masquant des librairies statiques en les encapsulant, on peut (presque) légitimement penser que l'utilisateur final peut faire le neuneu en l'utilisant sans tomber sur des erreurs cryptiques... Sur un exemple très simple, ça va, mais sur un "monstre" exportant des centaines de fonctions et types, ça peut vite devenir un enfer.

    Citation Envoyé par Médinoc Voir le message
    J'aime que mes pointeurs opaques soient typés, ça évite de les confondre.
    Personnellement, j'évite plutôt d'exposer les données privées, même dans une section "private:"... Je préfère que l'utilisateur ne voie que ce qu'il a à utiliser, et rien d'autre, pas même un #define quelconque.

    En général, j'utilise donc un .H "public" (exporté, documenté Doxygen et permettant d'avoir le manuel utilisateur), un .H "privé" (exclus du manuel utilisateur, mais présent en manuel du développeur) et un .CPP référençant les deux (inclus dans le manuel développeur bien sûr).

    Donc, en général, je n'ai pas besoin d'avoir un void* visible depuis l'extérieur, mais cela demande à être pris en compte dès la conception... Mais quand c'est pour résoudre ce genre de problèmes de link, il est plus rapide de passer en void* que de tout casser / refaire.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Librairies] Inserer lignes dans fichier RTF
    Par tit_oune dans le forum Bibliothèques et frameworks
    Réponses: 5
    Dernier message: 04/05/2012, 10h21
  2. [WIN32][D2005] Integrer une librairie C/C++ dans Delphi
    Par ZeGothMan dans le forum Langage
    Réponses: 8
    Dernier message: 30/03/2006, 13h56
  3. Inclusion de librairie sous visual
    Par petdelascar dans le forum C
    Réponses: 11
    Dernier message: 07/12/2005, 20h39
  4. Réponses: 5
    Dernier message: 25/04/2004, 00h57
  5. Inclusion de librairie ratée
    Par glop - pas glop dans le forum MFC
    Réponses: 21
    Dernier message: 15/02/2004, 18h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo