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

Langage C++ Discussion :

Importation de deux lib utilisant deux versions OpenGL différentes —> ça plante


Sujet :

Langage C++

  1. #1
    Membre éclairé Avatar de Suryavarman
    Homme Profil pro
    Développeur 3D
    Inscrit en
    Mai 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur 3D
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Mai 2006
    Messages : 233
    Par défaut Importation de deux lib utilisant deux versions OpenGL différentes —> ça plante
    Bonjour,
    Je suis sous linux, j'utilise cmake (gcc et clang).
    J'utilise wxWIdgets, Ogre, Cycles et plus tard il y en aura encore d'autres.
    Chacune de ces librairies utilisent OpenGL.

    Cycles utilise son propre dossier de dépendances. Il utilise peu les dépendances du système.

    Quand je compile Ogre et WxWIdgets, j'utilise au maximum les librairies du système.
    Ça fonctionnait à peu près bien avant d'inclure Cycles.

    Au premier appel à OpenGL ça plante directe. Même le try and catch ne permet pas de sortir l'erreur.
    Si je retire Cycles de mon projet, ça redevient normal.

    Je suppute que le problème vient de l’utilisation de différentes dépendances à OpenGL.

    J'ai l'impression que pour corriger ce problème, j'ai deux solutions :
    - Soit je compile Cycle avec les librairies utilisées par Ogre et wxWidgets.
    - Soit je trouve une solution pour isoler mes modules/.dll/.so du reste du programme sauf pour la partie qui m'intéresse.

    Je trouve la dernière solution plus satisfaisante à l'utilisation.
    Les modules pourront être gros et obèses comme Cycles, mais ceux qui créeront des modules n'auront pas à se soucier autant des dépendances du programme de base.
    Excepté que pour cette dernière solution, je ne vois pas trop comment faire et même si c'est possible.
    J'essaierais bien de faire plutôt que prévu un gestionnaire de plugins/modules qui pourront être chargés dynamiquement.
    Exemple avec Ogre3D :
    https://github.com/OGRECave/ogre/blo...lkanPlugin.cpp

    Mais est-ce que cela impactera le reste du programme ?

    Auriez-vous un avis sur cette problématique ?

  2. #2
    Membre éclairé Avatar de Suryavarman
    Homme Profil pro
    Développeur 3D
    Inscrit en
    Mai 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur 3D
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Mai 2006
    Messages : 233
    Par défaut
    J'ai copié ici le fil de mon raisonnement. allez directement à la fin si vous ne voulez pas être embété par ces réflexions.

    https://learn.microsoft.com/fr-fr/tr...c-link-library
    Il y a une notion de dépendances privé!?


    Les fonctions pour charger une .dll (windows), .dylib (mac), .js (emscripten) ou .so (linux) dynamiquement:

    https://github.com/OGRECave/ogre/blo...OgreDynLib.cpp


    WIN32:
    LoadLibraryEx(a, NULL, 0)
    GetProcAddress( a, b )
    !FreeLibrary( a )

    WINRT:
    LoadPackagedLibrary( stringToWstring(a).c_str(), 0 ))
    GetProcAddress( a, b )
    dlopen( a, RTLD_LAZY | RTLD_GLOBAL)
    dlsym( a, b )
    dlclose( a )

    apple et ios:
    mac_loadDylib( a )
    mac_loadFramework( a )
    dlsym( a, b )
    dlclose( a )

    Pour apple c'est bizarre je ne trouve pas de documentation si ce n'est l'utilisation de dlopen au lieu mac_loaDylib
    https://developer.apple.com/library/...Libraries.html
    https://developer.apple.com/library/...TP40001873-SW3



    CMake target private interface ?

    https://raw.githubusercontent.com/Ba...odernCMake.pdf

    Bon comme mes cibles sont toutes faites en privées. Il n'y a rien à essayer de plus pour moi.

    La commande pour voir les dépendances :
    ldd -v fichier_binaire

    résultat pour cycles:
    ldd -v cycles
    cycles utilise bien openGL par défaut:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    libGL.so.1 => /lib64/libGL.so.1 (0x00007f4630ab4000)
       libGLX.so.0 => /lib64/libGLX.so.0 (0x00007f4630950000)
    Dans le CMakeLists on peut voir cette volontée ici:
    scr/cmake/external_libs.cmake « Look in all library directories by default, except mesa and dpcpp which
    # can conflict with OpenGL and compiler detection. »
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      list(REMOVE_ITEM _cycles_lib_subdirs ${_cycles_lib_dir}/mesa)
      list(REMOVE_ITEM _cycles_lib_subdirs ${_cycles_lib_dir}/dpcpp)

    résultat pour mon application qui inclus cycles:
    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
     
        libGL.so.1 => /lib64/libGL.so.1 (0x00007f94b808c000)
    	libOpenGL.so.0 => /lib64/libOpenGL.so.0 (0x00007f94c42a0000)
    	libGLX.so.0 => /lib64/libGLX.so.0 (0x00007f94c426c000)
    	libGLU.so.1 => /lib64/libGLU.so.1 (0x00007f94c41fd000)
     
    	/lib64/libGLU.so.1:
    		libgcc_s.so.1 (GCC_3.0) => /lib64/libgcc_s.so.1
    		libm.so.6 (GLIBC_2.2.5) => /lib64/libm.so.6
    		libstdc++.so.6 (CXXABI_1.3.8) => /lib64/libstdc++.so.6
    		libstdc++.so.6 (CXXABI_1.3.9) => /lib64/libstdc++.so.6
    		libstdc++.so.6 (CXXABI_1.3) => /lib64/libstdc++.so.6
    		libstdc++.so.6 (GLIBCXX_3.4) => /lib64/libstdc++.so.6
    		libc.so.6 (GLIBC_2.7) => /lib64/libc.so.6
    		libc.so.6 (GLIBC_2.4) => /lib64/libc.so.6
    		libc.so.6 (GLIBC_2.14) => /lib64/libc.so.6
    		libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
    		libc.so.6 (GLIBC_2.11) => /lib64/libc.so.6
    		libc.so.6 (GLIBC_2.3.4) => /lib64/libc.so.6
    	/lib64/libOpenGL.so.0:
    		libc.so.6 (GLIBC_2.14) => /lib64/libc.so.6
    		libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
    	/lib64/libGLX.so.0:
    		libdl.so.2 (GLIBC_2.2.5) => /lib64/libdl.so.2
    		libc.so.6 (GLIBC_2.7) => /lib64/libc.so.6
    		libc.so.6 (GLIBC_2.14) => /lib64/libc.so.6
    		libc.so.6 (GLIBC_2.4) => /lib64/libc.so.6
    		libc.so.6 (GLIBC_2.3.4) => /lib64/libc.so.6
    		libc.so.6 (GLIBC_2.2.5) => /lib64/libc.so.6
    Du coup c'est bizarre les librairies d'opengl sont bien les mêmes qui sont utilisées.

    J'ai donc décider de comparer les dépendances via un script. Pour ce faire j'ai quitté cycles de mon projet, puis je me suis fait ce script en python.
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
     
    import os
    import sys
    import ma_dep
     
     
    def parse_log(log_path, deps=None):
        """
        Permet de parcourir et trier la liste des dépendances.
        :param log_path: Le chemin du fichier contenant la liste des dépendances.
        :param deps: La variable « deps » contient [le nom de la librairie sans l'extension] = [path_1, path_2, ...]
        """
        assert os.path.exists(log_path), f"Le fichier {log_path} n'existe pas."
        assert deps is not None, "La variable deps ne doit pas être nulle."
     
        with open(log_path) as file:
            for line in file.readlines():
                # "	libGLdispatch.so.0 => /lib64/libGLdispatch.so.0 (0x00007f112b1ba000)"
                split_result = line.split("=>")
                # [" libGLdispatch.so.0 ", " /lib64/libGLdispatch.so.0 (0x00007f112b1ba000)"]
                if len(split_result) == 2:
                    name = split_result[0].split('.')[0].strip().lstrip("lib")
                    path = split_result[1].split('(')[0].strip()
     
                    if name not in deps:
                        deps[name] = []
     
                    other_paths = deps[name]
                    same_file = False
                    for other_path in other_paths:
                        same_file = os.path.samefile(other_path, path)
     
                    if not same_file:
                        deps[name].append(path)
     
     
    def main(args):
        assert os.path.exists(args.exe_a_path), "Le chemin de la première application ne fonctionne pas."
        assert os.path.exists(args.exe_b_path), "Le chemin de la deuxième application ne fonctionne pas."
     
        log_directory = os.path.dirname(os.path.abspath(__file__))
     
        log_a = os.path.join(log_directory, os.path.basename(args.exe_a_path).split('.')[0] + ".txt")
        log_b = os.path.join(log_directory, os.path.basename(args.exe_b_path).split('.')[0] + ".txt")
     
        if sys.platform.startswith('linux'):
            ma_dep.call(f'ldd -v "{args.exe_a_path}" > {log_a}')
            ma_dep.call(f'ldd -v "{args.exe_b_path}" > {log_b}')
        elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
            assert False, "N'est pas implémentée."
        elif sys.platform.startswith('darwin'):
            assert False, "N'est pas implémentée."
     
        deps = {}
        parse_log(log_a, deps)
        parse_log(log_b, deps)
     
        for name, paths in deps.items():
            if len(paths) > 1:
                print(f"{name}: {paths}")
            else:
                print(f"{name}: unique")
     
     
    if __name__ == '__main__':
        import argparse
        arg_parser = argparse.ArgumentParser(description='Définition des chemins des deux exécutables pour comparer leurs '
                                                         'dépendances.')
        arg_parser.add_argument('--exe_a_path',
                                help="Le chemin du premier exécutable.",
                                type=str,
                                required=True)
     
        arg_parser.add_argument('--exe_b_path',
                                help="Le chemin du deuxième exécutable.",
                                type=str,
                                required=True)
     
        main(arg_parser.parse_args())
    Le résultat est que toutes les librairies communes utilisent bien les mêmes chemins.

    Du coup je sais pas trop quoi penser pour le moment.

    Peut être une corruption du contexte openGL. Pour voir si c'est ça, il suffit d'ajouter Cycles aux dépendances mais ne rien instancier ni même inclure quelque chose de cycles. En gros j'ai juste ajouté à la cible du projet la dépendance à Cycles.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    target_link_libraries(GUI PRIVATE API
                                      Cycles
                                      ${GUI_LINKER_LIBRARY})

    Le résultat est que ça plante au même endroit.

    Du coup j'ai relancé gdb et je n'avais pas vue ces messages de GDB:
    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
     
    Thread 1 "GUI" hit Breakpoint 21, Ogre::GLPlugin::install (this=0x3eac830) at /../Ma/dependencies/Ogre/RenderSystems/GL/src/OgreGLPlugin.cpp:50
    50	        mRenderSystem = OGRE_NEW GLRenderSystem();
    warning: can't find linker symbol for virtual table for `Ogre::GLRenderSystem' value
    warning: can't find linker symbol for virtual table for `Ogre::GLRenderSystem' value
    [...]
    warning: can't find linker symbol for virtual table for `Ogre::GLRenderSystem' value
    warning: can't find linker symbol for virtual table for `Ogre::GLRenderSystem' value
    warning: can't find linker symbol for virtual table for `Ogre::GLRenderSystem' value
     
    Thread 1 "GUI" hit Breakpoint 22, Ogre::GLRenderSystem::GLRenderSystem (this=0x3eb9ce0) at /../Ma/dependencies/Ogre/RenderSystems/GL/src/OgreGLRenderSystem.cpp:178
    warning: Source file is more recent than executable.
    178	        mGLSupport = getGLSupport(GLNativeSupport::CONTEXT_COMPATIBILITY);
     
    Thread 1 "GUI" received signal SIGABRT, Aborted.
    0x00007fffea79f4a0 in raise () from /lib64/libc.so.6

    Et voici l'état de la pile: (j'utilise CLion cette trace a été générée par la version de l'application compilée par gcc.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    raise 0x00007fffea79f4a0
    abort 0x00007fffea78a536
    llvm::report_fatal_error(llvm::Twine const&, bool) 0x00007ffff4878466
    vtable for llvm::raw_ostream 0x00007ffff7e5e450
    <unknown> 0x0000000000000000

  3. #3
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 440
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 440
    Par défaut
    Je ne connais bien que Windows.

    L'histoire des "dépendances privé" ce n'est qu'un n-ième mécanisme de "customisation/patching" du système de chargement des Dll par le chargeur de l'OS Windows.

    Avant de chercher une "solution" à un problème supposé, il faudrait commencer par caractériser le problème lui-même.

    Ce n'est pas forcement un putatif problème de versionning, ça peut, par exemple, être un problème de multi-threading, d'initialisation des globales, etc..., le problème ne pas venir de "Cycle".
    "Cycle" peut ne pas être la source du problème mais son révélateur, par exemple.

    Donc, caractérisez le problème avant de construire des châteaux en Espagne.

    Si vous pouvez déclencher le problème en mode Debug (informations de débugging complètes disponible), le débogueur devrait aider à voir la "vraie" source du problème.

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 440
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 440
    Par défaut
    Pas plus d'informations ?

  5. #5
    Membre éclairé Avatar de Suryavarman
    Homme Profil pro
    Développeur 3D
    Inscrit en
    Mai 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur 3D
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Mai 2006
    Messages : 233
    Par défaut
    Sisi, je suis toujours dessus. C'est pour un projet personnel donc dès que j'ai un peu de temps, j'avance.
    Il faudra que je trouve un moyen d'avoir libc.so.6 en debug. Sur mageia je peux l'avoir en .a mais ça ne me permet pas d'avoir les informations de débogage.
    J'ai donc profité de cette occasion pour ajouter un début de gestion de module à mon code. Cela me permettra de bien séparer les fichiers d'en tête. Ça permettra aussi d'activer et de désactiver les modules à loisir.
    Ça va être un peu long donc, je ne risque pas de répondre pendant un moment.

    Pour l'heure j'ai créer des .so séparés pour mon module ogre et mon module cycles. J'ai encore besoin d'inclure leur code dans mon application, ce qui ne me permet pas encore de m'assurer qu'un #define ou autre truc du genre pose un soucis.
    Quand j'aurais coupé les liens, là je reviendrais avec mon analyse.


    Sinon pour ogre j'ai cet appel à opengl qui fait planter libc.so.6
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Lancement d'Ogre3D:
    eglInitialize(mGLDisplay, &mEGLMajor, &mEGLMinor)
     
    mGLDisplay non nul
    mEGLMajor 1
    mEGLMinor 0
    Pour cycles je n'arrive pas encore à voir qu'elle est la fonction opengl qui fait planté libc.so.6
    J'ai recompiler en debug wxWidgets, mais c'est pas encore ça. Je doit aussi progresser sur cette partie là.

    Merci pour ta réponse.

  6. #6
    Membre éclairé Avatar de Suryavarman
    Homme Profil pro
    Développeur 3D
    Inscrit en
    Mai 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur 3D
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Mai 2006
    Messages : 233
    Par défaut
    J'ai peu avancé un peu

    Mon application est dorénavant dissociée de Cycles et Ogre3D. À la compilation, il n'y a plus d’édition de liens entre eux.
    J'ai créé un module Cycles et un module Ogre3D.

    Ça donne ça:


    Le module d'Ogre3D semble fonctionné si je ne charge pas Cycles.
    Le module Cycles se charge mais la création du contexte 3D fait planter l'application.

    Dans la capture vidéo on peut voir que Ogre plante dans le chargement d'une librairie dynamique.


    Sans grande conviction, je vais jouer un peu avec les options de dlopen
    https://linux.die.net/man/3/dlsym

    Pour le moment le problème n'est pas résolu.

    Il aurait été bien d'arriver à isoler ces librairies de l'une de l'autre. Après c'est peut-être un soucis entre wxWidgets et Cycles.

    Petite question:
    Pour m'assurer que les modules soient compilésautomatiquement, j'utilise dans cmake la fonction add_dependencies.
    En pratique je vois bien qu'aucun symbole des libraires n'est lié à l'application. Il faut bien charger dynamiquement le module pour que cela est lieu. Mais j'ai un doute.
    Du coup ma question est:
    Est-ce que add_dependencies ne fait que vérifier si les dépendances sont à jour ou il y aussi une étape de liens ?*
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    add_dependencies(MaEditor module_ogre
                              module_cycles
                              module_sample_cpp)

  7. #7
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    18 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 18 173
    Par défaut
    Je suis pas sûr que ça réponde à ton prob., mais si ça peut t'aider, tu peux forcer le chargement d'une bibliothèque de ton choix en remplacement de celle dans le dossier /lib(64) avec la variable d'environnement LD_PRELOAD.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  8. #8
    Membre éclairé Avatar de Suryavarman
    Homme Profil pro
    Développeur 3D
    Inscrit en
    Mai 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur 3D
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Mai 2006
    Messages : 233
    Par défaut
    J'ai été trop défaitiste :p
    https://linux.die.net/man/3/dlsym

    J'utilisais RTLD_GLOBAL du coup ça mettait à disposition les symboles chargés pour les autres bibliothèques.
    Du coup en utilisant l'opposé RTLD_LOCAL ça fonctionne, wxWidgets, Ogre et Cycles peuvent cohabiter.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    #define MA_DYNLIB_LOAD(a) dlopen(a, RTLD_LAZY | RTLD_LOCAL)
    Je ne suis pas encore sûr de l'option LAZY. Je verrais bien ça asse vite, j'ai des définitions de classes qui lors de l'ouverture de la librairie, devraient en principe s'ajouter au gestionnaire de classes.
    EDIT: ( sans l'option LAZY*le chargement du .so plante, dlopen déclare que l'argument est invalide.)

    Puis dans le futur j'aurais aussi à gérer les autres plateformes (MAC et WIN32).

    Merci de votre aide et attention. :)


    Pièce jointe 646998
    Images attachées Images attachées  

  9. #9
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 440
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 440
    Par défaut
    Ta gestion de "modules", c'est un truc fait maison ou c'est un framework ?
    Si c'est un framework, il y a des chances que les mécanismes sous-jacents changent en fonction de la plateforme pour que le code client de ce framework soit portable.

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

Discussions similaires

  1. Réponses: 7
    Dernier message: 13/01/2020, 12h49
  2. Réponses: 1
    Dernier message: 20/09/2013, 13h34
  3. Réponses: 6
    Dernier message: 16/08/2010, 17h42
  4. Réponses: 0
    Dernier message: 27/09/2007, 15h51
  5. Utilisation de deux versions de gcc sur la même plateforme
    Par Anouschka dans le forum Administration système
    Réponses: 5
    Dernier message: 04/05/2006, 11h32

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