2009-11-05 11 views
11

Comment puis-je obtenir le chemin de la bibliothèque partagée à partir de la bibliothèque elle-même? En d'autres termes, disons que la bibliothèque X est chargée en utilisant dlopen(), comment puis-je avoir accès au chemin qui a été utilisé pour charger la bibliothèque à partir de la bibliothèque elle-même?Chemin de la bibliothèque lors du chargement dynamique?

Notez que je ne peux pas avoir l'agent qui a chargé la bibliothèque en premier lieu ce paramètre.

MISE À JOUR: Voici manière qui fonctionne avec des variables statiques:

std::string wdir; 

namespace { 
    class dynamic_library_load_unload_handler { 
     public: 
       dynamic_library_load_unload_handler(){ 
        Dl_info dl_info; 
        dladdr((void *) NP_Initialize, &dl_info); 

        std::string path(dl_info.dli_fname); 
        wdir = path.substr(0, path.find_last_of('/') +1); 
       } 
       ~dynamic_library_load_unload_handler(){ 
        // Code to execute when the library is unloaded 
       } 
    } dynamic_library_load_unload_handler_hook; 
} 
+0

Existe-t-il une option pour définir une variable d'environnement avec ce chemin? Y at-il possibilité d'écrire un fichier tmp (je sais ... solution shtty :() – bua

+0

@bua: si la poussée vient à pousser, je vais probablement besoin de "trampoline" sur le système de fichiers ... mais j'essaie de – jldupont

+4

À ma grande déception, sur Android dli_fname ne contient pas le chemin du module, seul le nom du fichier –

Répondre

16

L'éditeur de liens dynamiques recherche en fait plusieurs endroits pour trouver chaque bibliothèque dynamique. Ceux-ci comprennent (de l'homme ld.so):

  • chemins donnés par la variable d'environnement LD_LIBRARY_PATH
  • chemins cuit dans la charge binaire de la bibliothèque sous l'entrée DT_RUNPATH
  • Le fichier cache de /etc/ld.so .cache
  • /lib et/usr/lib

Si vous voulez obtenir le chemin d'une bibliothèque partagée spécifique, je recommanderais la fonction dladdr. Sur la page de l'homme:

La fonction dladdr() prend un pointeur de fonction et tente de résoudre le nom et le fichier où il se trouve. Les informations sont stockées dans la structure Dl_info:

typedef struct { 
    const char *dli_fname; /* Pathname of shared object that 
           contains address */ 
    void  *dli_fbase; /* Address at which shared object 
           is loaded */ 
    const char *dli_sname; /* Name of nearest symbol with address 
           lower than addr */ 
    void  *dli_saddr; /* Exact address of symbol named 
           in dli_sname */ 
} Dl_info; 

Si aucun symbole adr correspondant n'a pu être trouvée, puis dli_sname et dli_saddr sont mis à NULL.

dladdr() renvoie 0 en cas d'erreur et non zéro en cas de succès.

Donc vous lui donnez juste un pointeur de fonction, et il vous donnera le nom du fichier qui le fournit et un tas d'autres informations. Ainsi, par exemple, vous pourriez avoir un constructeur dans un appel de la bibliothèque présente sur elle-même pour découvrir le chemin complet de la bibliothèque:

#define _GNU_SOURCE 
#include <dlfcn.h> 
#include <stdio.h> 

__attribute__((constructor)) 
void on_load(void) { 
    Dl_info dl_info; 
    dladdr((void *)on_load, &dl_info); 
    fprintf(stderr, "module %s loaded\n", dl_info.dli_fname); 
} 

Cette fonction fonctionne également sur Mac OS X avec la même sémantique.

+0

Fonctionne comme un charme ... merci! – jldupont

+0

MISE À JOUR: l'inconvénient que j'ai trouvé avec votre solution: d'autres cteurs ne sont pas Donc, si une variable C++ quelconque est déclarée statique, on ne peut pas y accéder avec 'on_load'. – jldupont

+2

@jldupont: Le '__attribute __ ((constructeur))' est exactement le même mécanisme que celui utilisé pour appeler les constructeurs de variables statiques en C++, sauf que gcc le rend aussi disponible en C de cette façon. L'ordre n'est donc pas spécifié entre les unités de traduction. Cependant, gcc vous permet de le spécifier en ajoutant une priorité comme '__attribute __ ((constructor (101)))'. La priorité des constructeurs peut être spécifiée en ajoutant '__attribute __ ((init_priority (500)))' à la classe, mais je ne trouve nulle part la priorité par défaut. Priorité inférieure signifie que le constructeur est appelé plus tôt et destructeur plus tard. –