¿Qué debo hacer si tengo dos bibliotecas que proporcionan funciones con nombres equivalentes?
vorbis_...
, sf_...
, sdl_...
). Esto es esencialmente lo que C ++ hace con los nombres de símbolos para funciones con espacios de nombres.
¿Qué debo hacer si tengo dos bibliotecas que proporcionan funciones con nombres equivalentes?
vorbis_...
, sf_...
, sdl_...
). Esto es esencialmente lo que C ++ hace con los nombres de símbolos para funciones con espacios de nombres.
Respuestas:
A propósito de los comentarios: Por "exportar" me refiero a hacer visibles los módulos que enlazan con la biblioteca --- equivalente a la extern
palabra clave en el alcance del archivo. Cómo se controla esto depende del sistema operativo y del enlazador. Y es algo que siempre tengo que buscar.
Es posible cambiar el nombre de los símbolos en un archivo de objeto usando objcopy --redefine-sym old=new file
(ver man objcopy).
Luego simplemente llame a las funciones usando sus nuevos nombres y vincule con el nuevo archivo de objeto.
En Windows, puede usar LoadLibrary () para cargar una de esas bibliotecas en la memoria y luego usar GetProcAddress () para obtener la dirección de cada función que necesita llamar y llamar a las funciones a través de un puntero de función.
p.ej
HMODULE lib = LoadLibrary("foo.dll");
void *p = GetProcAddress(lib, "bar");
// cast p to the approriate function pointer type (fp) and call it
(*fp)(arg1, arg2...);
FreeLibrary(lib);
obtendría la dirección de una función llamada bar en foo.dll y la llamaría.
Sé que los sistemas Unix admiten una funcionalidad similar, pero no puedo pensar en sus nombres.
dlopen
dlsym
y dlclose
. Sin embargo, la encapsulación en Unix puede no ser tan efectiva como en Windows.
He aquí un pensamiento. Abra una de las bibliotecas infractoras en un editor hexadecimal y cambie todas las apariciones de las cadenas infractoras por otra. Entonces debería poder usar los nuevos nombres en todas las llamadas futuras.
ACTUALIZACIÓN: Lo acabo de hacer en este extremo y parece funcionar. Por supuesto, no lo he probado a fondo; puede que no sea más que una buena manera de volar tu pierna con una escopeta de edición hexadecimal.
Suponiendo que usa linux, primero debe agregar
#include <dlfcn.h>
Declare la variable de puntero de función en el contexto adecuado, por ejemplo,
int (*alternative_server_init)(int, char **, char **);
Como dijo Ferruccio en https://stackoverflow.com/a/678453/1635364 , cargue explícitamente la biblioteca que desea usar ejecutando (elija sus banderas favoritas)
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
Lea la dirección de la función a la que desea llamar más tarde
sym = dlsym(dlhandle, "conflicting_server_init");
asignar y emitir de la siguiente manera
alternative_server_init = (int (*)(int, char**, char**))sym;
Llame de forma similar a la original. Finalmente, descargue ejecutando
dlclose(dlhandle);
No debe usarlos juntos. Si no recuerdo mal, el vinculador emite un error en tal caso.
No he intentado, pero una solución puede ser con dlopen()
, dlsym()
y dlclose()
que le permiten manipular mediante programación bibliotecas dinámicas. Si no necesita las dos funciones al mismo tiempo, puede abrir la primera biblioteca, usar la primera función y cerrar la primera biblioteca antes de usar la segunda biblioteca / función.
Si tiene archivos .o allí, una buena respuesta aquí: https://stackoverflow.com/a/6940389/4705766
Resumen:
objcopy --prefix-symbols=pre_string test.o
para cambiar el nombre de los símbolos en el archivo .o o
objcopy --redefine-sym old_str=new_str test.o
para cambiar el nombre del símbolo específico en el archivo .o.Este problema es la razón por la que c ++ tiene espacios de nombres. Realmente no hay una gran solución en c para 2 bibliotecas de terceros con el mismo nombre.
Si se trata de un objeto dinámico, es posible que pueda cargar explícitamente los objetos compartidos (LoadLibrary / dlopen / etc.) y llamarlo de esa manera. Alternativamente, si no necesita ambas bibliotecas al mismo tiempo en el mismo código, quizás pueda hacer algo con enlaces estáticos (si tiene los archivos .lib / .a).
Ninguna de estas soluciones se aplica a todos los proyectos, por supuesto.
¿Jurar? Hasta donde yo sé, no hay mucho que pueda hacer si tiene dos bibliotecas que exponen puntos de enlace con el mismo nombre y necesita vincular ambos.
Debería escribir una biblioteca contenedora alrededor de uno de ellos. Su biblioteca contenedora debe exponer símbolos con nombres únicos y no exponer los símbolos de los nombres no únicos.
Su otra opción es cambiar el nombre de la función en el archivo de encabezado y cambiar el nombre del símbolo en el archivo de objetos de la biblioteca.
De cualquier manera, para usar ambos, será un truco.
La pregunta se acerca a una década, pero hay nuevas búsquedas todo el tiempo ...
Como ya se respondió, objcopy con el indicador --redefine-sym es una buena opción en Linux. Consulte, por ejemplo, https://linux.die.net/man/1/objcopy para obtener la documentación completa. Es un poco torpe porque esencialmente está copiando toda la biblioteca mientras realiza cambios y cada actualización requiere que este trabajo se repita. Pero al menos debería funcionar.
Para Windows, cargar dinámicamente la biblioteca es una solución y una permanente como lo sería la alternativa dlopen en Linux. Sin embargo, tanto dlopen () como LoadLibrary () agregan código adicional que puede evitarse si el único problema son los nombres duplicados. Aquí, la solución de Windows es más elegante que el enfoque objcopy: simplemente dígale al enlazador que los símbolos en una biblioteca se conocen por algún otro nombre y use ese nombre. Hay algunos pasos para hacerlo. Debe crear un archivo def y proporcionar la traducción del nombre en la sección EXPORTACIONES. Consulte https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015, eventualmente será reemplazado por versiones más nuevas) o http://www.digitalmars.com/ctg/ctgDefFiles.html(probablemente más permanente) para obtener detalles de sintaxis completos de un archivo def. El proceso sería crear un archivo def para una de las bibliotecas, luego usar este archivo def para construir un archivo lib y luego vincularlo con ese archivo lib. (Para las DLL de Windows, los archivos lib solo se utilizan para vincular, no para ejecutar código). Consulte Cómo crear un archivo .lib cuando tenga un archivo .dll y un archivo de encabezado para el proceso de creación del archivo lib. Aquí la única diferencia es agregar los alias.
Tanto para Linux como para Windows, cambie el nombre de las funciones en los encabezados de la biblioteca a cuyos nombres se les asigna un alias. Otra opción que debería funcionar sería, en archivos que se refieran a los nuevos nombres, #define old_name new_name, #incluya los encabezados de la biblioteca cuyas exportaciones están siendo alias, y luego #undef old_name en el llamador. Si hay muchos archivos que utilizan la biblioteca, una alternativa más sencilla es crear un encabezado o encabezados que envuelvan las definiciones, las inclusiones y las indefs y luego usar ese encabezado.
¡Espero que esta información haya sido útil!
Nunca he usado dlsym, dlopen, dlerror, dlclose, dlvsym, etc., pero estoy mirando la página del manual y me da un ejemplo de cómo abrir libm.so y extraer la función cos. ¿Dlopen pasa por el proceso de búsqueda de colisiones? Si no es así, el OP podría simplemente cargar ambas bibliotecas manualmente y asignar nuevos nombres a todas las funciones que brindan sus bibliotecas.