2011-07-13 14 views
10

En mi programa tengo código como el siguiente¿Cómo obtener el nombre del archivo de la biblioteca absoluta correspondiente a una ruta relativa dada a dlopen?

/* libname may be a relative path */ 
void loadLib(char const *libname) { 
    void *handle = dlopen(libname); 
    /* ... */ 
    dlclose(handle); 
} 

Dentro /* .. */, necesito leer el archivo de mapa de memoria /proc/self/maps, para encontrar la dirección de memoria virtual en el que libname se correlaciona con, y también necesito para abrir el biblioteca para encontrar ciertas secciones en ella. Para esto, necesito el nombre absoluto que encontró dlopen al buscar en varios lugares (como, en el archivo de caché ldconfig). ¿Cómo puedo recibir ese nombre de archivo?


Esto es lo que finalmente terminó con (sí, este es el código C++, sin embargo, la etiqueta C tiene sentido para esta pregunta porque dlopen se utiliza tanto con C++ y C, y mi pregunta es elegible para ambos y POSIX lo especifica para C.).

boost::shared_ptr<void> dl; 
    if(void *handle = dlopen(libfile, RTLD_LAZY)) { 
     dl.reset(handle, &dlclose); 
    } else { 
     printdlerr(); 
     return -1; 
    } 

    /* update sofile to be an absolute file name */ 
    { 
     struct link_map *map; 
      dlinfo(dl.get(), RTLD_DI_LINKMAP, &map); 
     if(!map) { 
     return -1; 
     } 
     char *real = realpath(map->l_name, NULL); 
     if(!real) 
     return -1; 
     sofile.reset(real, &free); 
    } 

libfile es el nombre de archivo relativo/plain. El mapa producirá un nombre de archivo no simple (es decir, no foo.so pero puede ser ./foo.so). Después utilicé realpath para obtener el nombre de ruta absoluta final. ¡Funciona bien!

Respuesta

8

podría utilizar

... dlinfo(handle, RTLD_DI_LINKMAP, p) 
p->l_name ... 

donde p es de tipo Link_map **

ver dlinfo hombre para obtener detalles

+0

gracias. Lo hice y funciona. Mostraré mi camino final pronto. –

0

Una opción que se me ocurre está utilizando la función pathfind():

char *pathfind(const char *path, const char *name, const char *mode); 

DL se puede cargar desde uno de tres lugares: directorio actual, el directorio donde se encuentra el ejecutivo y LD_LIBRARY_PATH - se puede comprobar los dos últimos - y use el pathfind con el getenv("LD_LIBRARY_PATH") para el parámetro path para intentar buscar otro.

+0

¿Y dónde se encuentra 'pathfind'? No puedo encontrarlo en la documentación de Posix, ni siquiera en los documentos de Linux. –

1

La única solución es imitar el algoritmo del sistema. Esto no es tan difícil como suena (aunque, como siempre, el diablo está en los detalles ): Yo uso el siguiente para encontrar la ruta del ejecutable:

std::string retval = our_argv0; 
if (!isAbsolute(retval)) 
{ 
    char const* tmp = getenv("PATH"); 
    if (tmp == NULL) 
     throw std::runtime_error("$PATH not set"); 
    std::vector<std::string> dirs(split(std::string(tmp), ":")); 
    std::vector<std::string>::const_iterator i = dirs.begin(); 
    while (i != dirs.end() 
      && ! access((*i + '/' + retval).c_str(), X_OK) == 0) 
     ++ i; 
    if (i == dirs.end()) 
     throw std::runtime_error("Cannot find load path"); 
    retval = *i + '/' + retval; 
} 
return std::string(
    retval.begin(), 
    std::find(retval.rbegin(), retval.rend(), '/').base()); 

usted debería ser capaz de adaptarlo para una biblioteca, utilizando el nombre de la biblioteca en lugar de argv[0], LD_LIBRARY_PATH en lugar de PATH y el valor predeterminado apropiado en lugar de arrojar si no está configurado. Hay son casos especiales que no maneja, pero lo anterior funciona para que podamos encontrar el ejecutable. (split y isAbsolute son otras funciones de en nuestra biblioteca, que hacen las cosas obvias.)

Cuestiones relacionadas