2009-11-05 15 views
11

¿Cómo puedo obtener la ruta de la biblioteca compartida desde la misma biblioteca?ruta de la biblioteca cuando se carga dinámicamente?

En otras palabras, digamos que la biblioteca X se carga utilizando dlopen(), ¿cómo puedo obtener acceso a la ruta que se utilizó para cargar dicha biblioteca desde la misma biblioteca?

Tenga en cuenta que no puedo tener el agente que se ha cargado la biblioteca en el primer lugar mano me este parámetro.

ACTUALIZADO: Aquí está la manera que funciona con variables estáticas:

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

¿Hay una opción para establecer alguna variable de entorno con ese camino? ¿Existe la posibilidad de escribir algún archivo tmp (sé ... :(solución shtty) – bua

+0

@bua: si el empuje viene empujar, que probablemente tendrá que "cama elástica" en el sistema de archivos ... pero yo estoy tratando de . encontrar una forma más limpia – jldupont

+4

Para mi decepción, en dli_fname Android no contiene la ruta del módulo, sólo el nombre de archivo –

Respuesta

16

El enlazador dinámico en realidad busca en varios lugares para encontrar cada biblioteca dinámica. Estos incluyen (de hombre ld.so):

  • Caminos dada por la variable de entorno LD_LIBRARY_PATH
  • Caminos al horno en la carga binario la biblioteca bajo la DT_RUNPATH entrada
  • El archivo de caché /etc/ld.so .cache
  • /lib y/usr/lib

Si desea obtener la ruta para una biblioteca compartida específica, recomendaría la función dladdr. Desde la página del manual:

La función dladdr() toma un puntero a función y trata de resolver nombre y archivo en el que se encuentra. La información se almacena en la estructura 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 se pudo encontrar ningún símbolo a juego addr, a continuación, dli_sname y dli_saddr se ponen a NULL.

dladdr() devuelve 0 en caso de error, y distinto de cero en caso de éxito.

Así que solo tiene que darle un puntero a la función, y le dará el nombre del archivo que lo suministra y un montón de información adicional. Así, por ejemplo, usted podría tener un constructor en una biblioteca llamada esto en sí mismo para averiguar la ruta completa de la biblioteca:

#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); 
} 

Esta función también funciona en OS X con la misma semántica.

+0

funciona como un encanto ... gracias – jldupont

+0

ACTUALIZADO:.! el inconveniente que encontré con su solución: otros ctors no son llamado antes de su 'on_load'. Por lo tanto, si una variable C++ de algún tipo se declara estática, no se puede acceder desde' on_load '. Puede ser molesto. – jldupont

+2

@jldupont: El '__attribute__ ((constructor))' es exactamente el mismo mecanismo utilizado para llamar a los constructores de variables estáticas en C++, excepto que gcc también lo hace disponible en C de esta manera. Entonces, el orden no se especifica en las unidades de traducción. Sin embargo, gcc te permite especificarlo agregando una prioridad como '__attribute __ ((constructor (101)))'. La prioridad de los constructores se puede especificar agregando '__attribute__ ((init_priority (500)))' a la clase, pero no puedo encontrar la prioridad predeterminada en ninguna parte. Menor prioridad significa que el constructor se llama antes y el destructor después. –

Cuestiones relacionadas