2011-06-30 12 views
40

I 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.Vinculación de dos bibliotecas compartidas con algunos de los mismos símbolos

Por ejemplo, ambas bibliotecas definen una función global bar() que cada una de las llamadas 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 solicitud contra Lib1.so y luego Lib2.so la aplicación de barras de Lib1.so se llama incluso cuando llame al 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?

Respuesta

40

Hay varias maneras de resolver este:

  • Pass -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 con 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 al, por lo que se puede hacer referencia a ellos desde fuera de la biblioteca.

  • utilizar un script versión para marcar símbolos como local de a la biblioteca, por ejemplo, use algo como: {local: bar;}; y pase --version-script=versionfile al vinculador. Los símbolos son no exportados.

  • Marcar símbolos con un approppiate visibilidad (GCC info page for visibility), que será o bien ocultos, interna, o protegida.protegidas símbolos de visibilidad se exportan como .protected, ocultos símbolos no se exportan, y internos símbolos no se exportan y que no compromete a llamar desde fuera de la biblioteca, incluso de forma indirecta a través de la función punteros.

Puede verificar qué símbolos se exportan con objdump -T.

+0

Hola, ¿puedes decirme si esto también se aplica al clang? –

3

Tendrá que 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.

Puede ser menos estresante acceder a las libs resultantes a través de dlopen con las opciones adecuadas, también.

+0

Gracias tanto! Solo la opción -Bsymbolic (pasada al enlazador usando la opción -Wl) para ambos enlaces de biblioteca compartida resolvió el problema para mí. – drewag

0

Otra forma de resolver este problema es usar macro para cambiar el espacio de nombres.

Requisitos previos

  • Todos los elementos (funciones, clases, variables globales, ...) se encuentran 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 de espacio de nombres para definir a 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 qué usar esto en vez de otras soluciones

  • Cuando la biblioteca problemática se utiliza (al menos parcialmente) en los archivos de cabecera (por ejemplo, plantillas, inline, ...); 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/ninguno para otras soluciones (no debería suceder con nuestras CPU intel/amd de 32/64 bits, pero parece que de la búsqueda de Google pueden surgir otras plataformas).

problemas potenciales

  • Podría ser problemático utilizar tanto en la versión de un archivo CPP de su ejecutable; #include "my_lib.h" probablemente usa macro para proteger contra la inclusión múltiple y no definirlas para evitar esto podría causar muchos problemas diferentes (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 sustituir respuesta aceptado actualmente (de ninjalj, se siente libre de copiar-pegar), sino que se extienden con otro enfoque.
  • La razón principal por la que publiqué esta respuesta es que me encontré con este problema hoy, pero la respuesta no ayudó porque el código problemático estaba en los archivos de encabezado.
  • Mi fuente: https://spin.atomicobject.com/2014/06/03/static-linking-c-plus-plus/
Cuestiones relacionadas