library - Vinculación de dos bibliotecas compartidas con algunos de los mismos símbolos
make shared libraries (3)
Deberá crear dos libs compartidas ''wrapper'', una para cada una de sus libs existentes. Cada uno debe construirse con una lista dinámica que enumera solo algunos símbolos que no entran en conflicto que definen una API. También necesitará -Bsymbolic para evitar cualquier combinación global.
También podría ser menos estresante acceder a las libs resultantes a través de dlopen con opciones adecuadas.
Me enlace con dos bibliotecas compartidas diferentes. Ambas bibliotecas definen algunos símbolos que comparten un nombre pero tienen implementaciones diferentes. No puedo hacer que cada biblioteca use su propia implementación sobre la otra.
Por ejemplo, ambas bibliotecas definen una bar()
función global bar()
que cada una llama internamente. La biblioteca uno lo llama desde foo1()
y la biblioteca dos lo llama desde foo2()
.
Lib1.so:
T bar
T foo1() // calls bar()
Lib2.so:
T bar
T foo2() // calls bar()
Si vinculo mi aplicación con Lib1.so y luego con Lib2.so se llama a la implementación de barra desde Lib1.so incluso cuando se llama a foo2()
. Si, por otro lado, vinculo mi aplicación con Lib2.so y luego con Lib1.so, entonces la barra siempre se llama desde Lib2.so.
¿Hay alguna manera de hacer que una biblioteca siempre prefiera su propia implementación por encima de cualquier otra biblioteca?
Hay varias formas de resolver esto:
Pase
-Bsymbolic
o-Bsymbolic-functions
al enlazador. Esto tiene un efecto global: cada referencia a un símbolo global (del tipo de función para-Bsymbolic-functions
) que se puede resolver a un símbolo en la biblioteca se resuelve con ese símbolo. Con esto, usted pierde la capacidad de interponer llamadas de la biblioteca interna a esos símbolos usando LD_PRELOAD. Los símbolos todavía se exportan , por lo que se puede hacer referencia desde fuera de la biblioteca.Use un script de versión para marcar símbolos como locales en la biblioteca, por ejemplo, use algo como:
{local: bar;};
y pase--version-script=versionfile
de--version-script=versionfile
al enlazador. Los símbolos no son exportados.Marque símbolos con una visibilidad apropiada ( página de información de GCC para visibilidad ), que estarán ocultos , internos o protegidos . los símbolos de visibilidad protegidos se exportan como símbolos
.protected
, ocultos , no se exportan , y los símbolos internos no se exportan y se compromete a no llamarlos desde fuera de la biblioteca, incluso indirectamente a través de punteros de función.
Puede verificar qué símbolos se exportan con objdump -T
.
Otra forma de resolver este problema es usar macro para cambiar el espacio de nombres.
Requisitos previos
- Todos los elementos (funciones, clases, variables globales, ...) están en un espacio de nombres.
- La biblioteca no depende en gran medida de macros en los encabezados.
Solución
- Al compilar la biblioteca, defina la macro con el nombre del espacio de nombres para definirla como algo diferente. Por ejemplo, si el espacio de nombres es LibNS, use
-DLibNS=LibNSv1
para un caso y-DLibNS=LibNSv2
para el otro. Al usar bibliotecas en el código, defina macro según su situación actual;
#define LibNS LibNSv1 #include "my_lib.h" #undef LibNS
Razones por las cuales usar esto en lugar de otras soluciones
- Cuando la biblioteca problemática se utiliza (al menos parcialmente) en archivos de encabezado (por ejemplo, plantillas, líneas, ...); cuando los incluye en el código de su ejecutable, el solucionador no tiene idea de si estas funciones deberían invocarse desde Lib1.so o Lib2.so.
- Su compilador tiene soporte deficiente / inexistente para otras soluciones (no debería suceder con nuestras CPU intel / amd de 32/64 bits, pero parece que de la búsqueda en Google es posible que otras plataformas tengan el problema).
Problemas potenciales
- Puede ser problemático usar ambas versiones en un archivo cpp del ejecutable;
#include "my_lib.h"
probablemente usa macro para proteger contra inclusión múltiple y no definirlos para evitar esto podría causar muchos problemas diferentes (el autor de la biblioteca podría cambiar el nombre de la macro en el futuro, el encabezado define algunas otras macros, etc.).
Notas
- Esto no pretende reemplazar la respuesta actualmente aceptada (de ninjalj; siéntase libre de copiarla y pegarla), pero amplíela con otro enfoque.
- La razón principal por la que publiqué esta respuesta es que hoy me encontré con este problema, pero la respuesta no ayudó porque el código problemático se encontraba en los archivos de encabezado.
- Mi fuente: https://spin.atomicobject.com/2014/06/03/static-linking-c-plus-plus/