headers - learncpp
¿Qué debo hacer si dos bibliotecas proporcionan una función con el mismo nombre generando un conflicto? (12)
¿Qué debo hacer si tengo dos bibliotecas que proporcionan funciones con nombres equivalentes?
¿Jurar? Por lo que sé, no hay mucho que pueda hacer si tiene dos bibliotecas que exponen puntos de enlace con el mismo nombre y necesita vincular ambos.
Aquí hay un pensamiento. Abra una de las librerías ofensivas en un editor hexadecimal y cambie todas las ocurrencias de las cadenas ofensivas a otra cosa. Debería poder usar los nuevos nombres en todas las llamadas futuras.
ACTUALIZACIÓN: Acabo de hacerlo 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 la pierna con una escopeta de hexedito.
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 exclusivos.
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, va a ser un trabajo de hackeo.
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 a la 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 llámala.
Sé que los sistemas Unix admiten una funcionalidad similar, pero no puedo pensar en sus nombres.
Es posible cambiar el nombre de los símbolos en un archivo de objeto utilizando objcopy --redefine-sym old=new file
(see man objcopy).
Luego solo llame a las funciones usando sus nuevos nombres y enlace con el nuevo archivo objeto.
Este problema es la razón por la cual c ++ tiene espacios de nombres. Realmente no hay una gran solución en c para 2 libs 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, puede hacer algo con enlaces estáticos (si tiene los archivos .lib / .a).
Ninguna de estas soluciones se aplica a todos los proyectos, por supuesto.
La pregunta se acerca a una década de antigüedad, pero hay nuevas búsquedas todo el tiempo ...
Como ya se respondió, objcopy con la bandera --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 la alternativa de dlopen en Linux. Sin embargo, tanto dlopen () como LoadLibrary () agregan un código adicional que se puede evitar si el único problema son los nombres duplicados. Aquí la solución de Windows es más elegante que el enfoque de objcopy: simplemente dígale al vinculador que los símbolos en una biblioteca son conocidos 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 detalles completos de sintaxis de un archivo def. El proceso sería crear un archivo def para una de las bibliotecas y luego usar este archivo def para compilar 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 la ejecución de 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 cuyos nombres están siendo alias. Otra opción que debería funcionar sería, en los archivos que hacen referencia a los nombres nuevos, #define old_name new_name, #include los encabezados de la biblioteca cuyas exportaciones están siendo alias, y luego #undef old_name en la persona que llama. Si hay muchos archivos que usan la biblioteca, una alternativa más fácil es crear un encabezado o encabezados que ajuste las definiciones, los elementos incluidos y los elementos no definidos y luego use ese encabezado.
Espero que esta información haya sido útil.
No deberías usarlos juntos. Si recuerdo correctamente, el vinculador emite un error en tal caso.
No lo intenté, pero una solución puede ser con dlopen()
, dlsym()
y dlclose()
que te permiten manejar las bibliotecas dinámicas de manera programática. 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.
Nunca he usado dlsym, dlopen, dlerror, dlclose, dlvsym, etc., pero estoy mirando la página man, y da un ejemplo de apertura de libm.so y extracción de la función cos. ¿Dlopen pasa por el proceso de buscar colisiones? Si no lo hace, el OP podría simplemente cargar ambas bibliotecas de forma manual y asignar nuevos nombres a todas las funciones que proporcionan sus bibliotecas.
Si tiene archivos .o allí, una buena respuesta aquí: https://.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.
Suponiendo que usas Linux, primero debes agregar
#include <dlfcn.h>
Declarar la variable de puntero de función en el contexto adecuado, por ejemplo,
int (*alternative_server_init)(int, char **, char **);
Al igual que Ferruccio declaró en https://.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;
Llamar de manera similar que el original. Finalmente, descargue ejecutando
dlclose(dlhandle);
- Si controla uno o ambos: edite uno para cambiar el nombre y vuelva a compilar O, de manera equivalente, vea las respuestas de Ben y las respuestas unknown , que funcionarán sin acceso al código fuente.
- Si no controla ninguno de ellos, puede envolver uno de ellos. Eso es compilar otra biblioteca (¡ estáticamente enlazada !) Que no hace nada excepto reexportar todos los símbolos del original excepto el ofensivo, que se alcanza a través de un contenedor con un nombre alternativo. Qué lío.
- Agregado más tarde: como qeek dice que está hablando de bibliotecas dinámicas, las soluciones sugeridas por Ferruccio y mouviciel son probablemente las mejores. (Parece que viví hace mucho tiempo cuando el enlace estático era el predeterminado. Colorea mi pensamiento).
A propósito de los comentarios: con "exportar" me refiero a hacer visibles los módulos vinculados a la biblioteca, equivalentes a la palabra clave extern
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.