Vincular dos bibliotecas compartidas con algunos de los mismos símbolos


Enlazo con dos bibliotecas compartidas diferentes. Ambas bibliotecas definen algunos símbolos que comparten un nombre pero tienen diferentes implementaciones. No puedo hacer que cada biblioteca use su propia implementación sobre la otra.

Por ejemplo, ambas bibliotecas definen una función global bar() que cada una llama internamente. Library one lo llama desde foo1() y library two lo llama desde foo2().

Lib1.so:

T bar
T foo1()     // calls bar()

Lib2.so:

T bar
T foo2()     // calls bar()

Si enlazo mi solicitud contra Lib1.so y luego Lib2.so la implementación de la barra desde Lib1.so se llama incluso cuando se llama foo2(). Si, por otro lado, enlazo mi solicitud contra Lib2.so y luego Lib1.so, entonces bar siempre se llama desde Lib2.so.

¿Hay alguna manera de hacer que una biblioteca prefiera siempre su propia implementación por encima de cualquier otra biblioteca?

Author: Trilarion, 0000-00-00

3 answers

Hay varias maneras de resolver esto:

  • Pasar -Bsymbolic o -Bsymbolic-functions para el enlazador. Esto tiene un efecto global: cada referencia a un símbolo global (de tipo de función para -Bsymbolic-functions) que se puede resolver a un símbolo en la biblioteca se resuelve a ese símbolo. Con esto se pierde la capacidad de interponer llamadas a bibliotecas internas a esos símbolos usando LD_PRELOAD. Los símbolos todavía se exportan, por lo que pueden ser referenciados desde fuera del biblioteca.

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

  • Marcar símbolos con una visibilidad correspondiente (GCC info page for visibility), que estará bien oculto, interno , o protegido. protegido símbolos de visibilidad se exportan como .protected, los símbolos 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 comprobar qué símbolos se exportan con objdump -T.

 42
Author: ninjalj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-30 19:27:24

Tendrás que crear dos librerías compartidas 'wrapper', una para cada una de tus librerías existentes. Cada uno debe construirse con una list dynamic-list que enumera solo unos pocos símbolos no conflictivos que definen una API. También necesitará-Bsymbolic para evitar cualquier combinación global.

Podría ser menos estresante acceder a las bibliotecas resultantes a través de dlopen con opciones adecuadas, también.

 3
Author: bmargulies,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-30 17:20:38

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 las macros en las cabeceras.

Solución

  • Al compilar la biblioteca, defina macro con nombre de espacio de nombres para definirla a algo diferente. Por ejemplo, si el espacio de nombres es LibNS, use -DLibNS=LibNSv1 para un caso y -DLibNS=LibNSv2 para el otro.
  • Cuando use bibliotecas en el código, defina macro de acuerdo con su situación actual;

    #define LibNS LibNSv1
    #include "my_lib.h"
    #undef LibNS
    

Razones por las que usar esto en lugar de otras soluciones

  • Cuando la biblioteca problemática se usa (al menos parcialmente) en archivos de encabezado (por ejemplo plantillas, líneas internas, ...); cuando las incluyes en el código de tu ejecutable, el solucionador no tiene idea de si estas funciones deben ser llamadas desde Lib1.so o Lib2.so.
  • Su compilador tiene soporte pobre/ninguno para otras soluciones (no debería suceder con nuestras CPU intel/amd de 32/64 bits, pero parece por la búsqueda de Google que algunas otras plataformas podrían tener el problema).

Problemas potenciales

  • Podría ser problemático usar ambas versiones en un archivo cpp de su ejecutable; #include "my_lib.h" probablemente use macro para protegerse contra la inclusión múltiple y desactivarlas 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), sino extenderla 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ó debido a que 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 /
 0
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-20 10:28:29