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

Linux Discussion :

Pb : Modification dynamique du LD_LIBRARY_PATH pour dlopen()


Sujet :

Linux

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 58
    Points : 50
    Points
    50
    Par défaut Pb : Modification dynamique du LD_LIBRARY_PATH pour dlopen()
    Bonjour,

    Voilà mon problème. Je fais un petit programme qui reçoit en entrée un ficher XML contenant entre autres une liste de librairies (.so) à charger.
    Ce fichier contient également le ou les répertoires dans le(s)quel(s) on peut trouver ces librairies.
    Un exemple de fichier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    <Appli>
     <LibDir mode="relative" name="./Lib" />
     <LibDir mode="absolute" name="/home/noodles/Lib" />
     <Dependency lib="action1.so" />
     <Dependency lib="action2.so" /> 
    </Appli>
    Mon programme parse ce petit fichier, puis tente de charger dynamiquement les librairies.

    Ma première idée était que le programme rajoute dans la variable d'environnement LD_LIBRARY_PATH les chemins fournis, pour pouvoir charger les librairies.
    J'ai donc procédé comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    string ld = "LD_LIBRARY_PATH=";
    string oldPath = getenv("LD_LIBRARY_PATH");
    if(strlen(oldPath))
    {
      ld += oldPath;
      ld += ":";
    }
    ld += libDir; //libDir parsé depuis le XML
    if (putenv(const_cast<char *>(ld.c_str())) == -1)
      printf("putenv failed \n");
    Ce code marche bien (j'ai vérifié en faisant getenv("LD_LIBRARY_PATH")). Mais quand je fais dlopen(), il me dit qu'il ne trouve pas la librairie, comme si le nouveau LD_LIBRARY_PATH n'était pas pris en compte. Après quelques recherches, j'ai l'impression que le programme charge les variables d'environnement à son lancement, et donc ne les met pas à jour.

    J'ai même essayé d'aller voir ce qu'il y a dans la variable gloable char** environ après le putenv, et les modifications sont prises en compte!
    Donc je ne comprends pas trop!

    Je me suis donc dis que j'allais mettre directement dans le XML, les chemins complets des librairies. Malheureusement, cela ne marche pas non plus parce que quand dlopen() essaie de resoudre les dépendances, il n'y a pas ce qu'il faut dans le LD_LIBRARY_PATH!


    Donc pour résumer, ma question est : peut-on en C (ou C++), modifier la variable LD_LIBRARY_PATH qui est prise en compte par dlopen() pour ajouter des chemins à prendre en compte...

    Merci

    Noodles

  2. #2
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Ok tu as deux solutions :

    - Prendre tous tes répertoires et ajouter dans le xterm tes répertoires dans LD_LIBRARY_PATH.

    - Lancer ton programme avec tes dlopen et voir si cela passe.

    Je te dis cela puisque j'utilise putenv tous les jours et cela fonctionne très bien chez moi donc je ne vois pas pourquoi cela ne fonctionnerait pas chez toi.

    Jc

  3. #3
    Membre expérimenté
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Points : 1 664
    Points
    1 664
    Par défaut
    EDIT: l'exemple donne ici est incorrect, cf. la reponse de fearyourself qui suit.

    Voici un petit exemple en C qui force LD_LIBRARY_PATH a ne contenir que /usr/lib et accede ensuite a libm.so sans lui donner le chemin complet (contrairement a ce que je disais dans le forum C, si le chemin n'est pas complet, dlopen() utilise effectivement LD_LIBRARY_PATH).
    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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <dlfcn.h>
     
    /*
     * gcc -W -Wall -pedantic -rdynamic so.c -o so -ldl
     *
     *
     * overwrite environment variable LD_LIBRARY_PATH
     * with a single directory.
     */
    static int force_library_path(const char *path)
    {
      int ret = -1; /* error code */
      char keyval[100];
      const char *envvar = "LD_LIBRARY_PATH";
      int status;
     
      sprintf(keyval, "%s= %s", envvar, path);
      status = putenv(keyval);
      if (status == 0)
      {
        /*
         * print the new value of envvar
         */
        char *pathv = getenv(envvar);
     
        if (pathv != NULL)
        {
          printf("Value of %s is %s.\n", envvar, pathv);
          ret = 0; /* success */
        }
      }
     
      return ret;
    }
     
    int main(void)
    {
      int ret = EXIT_FAILURE;
     
      int status = force_library_path("/usr/lib");
     
      if (status != 0)
      {
        fprintf(stderr, "Failed to force library path.\n");
      }
      else
      {
        void *handle;
     
        handle = dlopen ("libm.so", RTLD_LAZY);
        if (handle == NULL)
        {
          fprintf(stderr, "%s\n", dlerror());
        }
        else
        {
          double (*cosine)(double);
          char *error;
     
          cosine = dlsym(handle, "cos");
          error = dlerror();
          if(error != NULL)
          {
            fprintf(stderr, "%s\n", error);
          }
          else
          {
            printf("%f\n", cosine(2.0));
            dlclose(handle);
            ret = EXIT_SUCCESS;
          }
        }
      }
     
      return ret;
    }
    Comme prevu, la sortie produite est:
    Value of LD_LIBRARY_PATH is /usr/lib.
    -0.416147
    Donc l'appel a putenv() met bien a jour la variable d'environnement pour la suite du programme. Ton probleme doit venir d'ailleurs.

  4. #4
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Citation Envoyé par DaZumba
    Donc l'appel a putenv() met bien a jour la variable d'environnement pour la suite du programme. Ton probleme doit venir d'ailleurs.

    Désolé mais cela ne prouve rien. dlopen regardera de toute facon dans /lib et /usr/lib s'il ne trouve pas ce qu'il cherche.

    Donc mettre /usr/lib dans LD_LIBRARY_PATH provoque simplement un changement dans l'ordre de recherche dans les répertoire.

    [EDIT]D'ailleurs je viens de tester avec une bibliothèque dynamique perso et ton code ne fonctionne pas. Cela semble plus compliquer que ce qu'on peut croire...[/EDIT]
    Jc

  5. #5
    Membre expérimenté
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Points : 1 664
    Points
    1 664
    Par défaut
    Citation Envoyé par fearyourself
    Désolé mais cela ne prouve rien. dlopen regardera de toute facon dans /lib et /usr/lib s'il ne trouve pas ce qu'il cherche.
    Ah oui c'est une bonne remarque, cela. Je modifie mon post pour prevenir qu'il est incorrect.

    D'ailleurs je viens de tester avec une bibliothèque dynamique perso et ton code ne fonctionne pas. Cela semble plus compliquer que ce qu'on peut croire...
    En effet. Je viens de tester avec une biblio perso egalement, placee dans /tmp, et ecraser LD_LIBRARY_PATH pour y mettre /tmp ne permet pas a dlopen() de trouver ma biblio. Par contre, faire un export LD_LIBRARY_PATH=/tmp avant de faire tourner le programme arrange les choses, comme Noodles l'avait fait remarquer. Malheureusement, la manpage de dlopen() chez moi n'est pas tres explicite:
    Citation Envoyé par man dlopen
    The file argument is used to construct a pathname to the object file. If file contains a slash character, the file argument is used as the pathname for the file. Otherwise, file is used in an implementation-defined manner to yield a pathname.
    Mouais. Je ne fais pas avancer le truc...

  6. #6
    Membre expérimenté
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Points : 1 664
    Points
    1 664
    Par défaut
    Ok, apres un petit coup de Google, il semble que putenv() ne met en effet pas a jour l'environnement dans lequel le programme evolue (c'est apparemment impossible). Par contre, elle permet d'installer un environnement avant d'appeler un autre programme (via execlp() par exemple). J'aurais appris quelque-chose au moins !

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 58
    Points : 50
    Points
    50
    Par défaut
    Bonjour à tous,

    Désolé d'avoir été absent si longtemps, j'étais en long week-end...

    Je suis content de voir que vous avez effectivement bien compris le problème.
    D'après tout ce que j'ai pu voir sur google, il est possible de modifier les variables d'environnement... mais uniquement pour lancer un exec derrière et pas pour le programme en cours. Donc ça c'est pas cool.

    A partir de là, j'ai plusieurs solutions :
    • Faire un script qui va d'abord parser le XML, ajouter les chemins fournis dans le LD_LIBRARY_PATH et lancer mon programme. Cela m'embête un peu de rajouter cette couche spécifiquement pour ça. J'aurais préféré que tout se fasse dans le programme.
    • Gérer moi-même les dépendances :
      • Propre : trouver une fonction C capable de me lister les dépendances d'une librairie et les charger (récursivement) en tenant compte des chemins que j'ai récupéré dans le XML.
      • Moins propre : Récupérer les messages d'erreur lorsqu'une dépendance ne se charge pas, traiter ce message pour récupérer le nom de la librairie et la charger moi-même en tenant compte des chemins fournis.
      • Infaisable : Aller jeter un oeil dans le code de dlopen() pour voir comment il traite les dépendances et le récupérer en le modifiant pour prendre en compte les chemins que je veux.
      • Très moche : Compiler les librairies que je vais charger en static pour qu'elles n'aient pas de dépendances externes...


    Voilà, dites-moi ce que vous en pensez et si vous avez d'autres idées, je suis preneur!

    Noodles

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    58
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 58
    Points : 50
    Points
    50
    Par défaut
    Bon finalement, gérer les dépendances soi-même c'est très galère.
    En effet, si par exemple lib1.so dépende de lib0.so. Même si je charge d'abord lib0 moi-même (avec un dlopen), le dlopen de lib1 voudra quand même charger lib0. Et si on suppose que lib0 n'est pas dans le LD_LIBRARY_PATH, c'est mort.

    Donc finalement je me suis rabattu vers la toute première solution, et je suppose que lorsque le programme démarre, il y a tout ce qu'il faut dans le LD_LIBRARY_PATH (soi on a mis manuellement, soit on lance un script qui le fait).

    Ca m'embête un peu de pas avoir réussi mais pour le moment, je ne vois pas de solution...

Discussions similaires

  1. Réponses: 5
    Dernier message: 01/08/2007, 20h31
  2. Modification dynamique de la couche alpha
    Par Daedar dans le forum OpenGL
    Réponses: 6
    Dernier message: 22/10/2005, 14h22
  3. [JTree] Modification dynamique du texte à afficher
    Par jIdJo dans le forum Composants
    Réponses: 2
    Dernier message: 17/06/2005, 16h49
  4. Réponses: 12
    Dernier message: 26/04/2004, 08h32

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