2011-12-16 15 views
9

sto lavorando su un progetto di C++ che ha bisogno di due librerie di terze parti (libfoo.so e libbar.so). Il mio sistema operativo è Linux.Collegamento librerie con dependecies incompatibili

libfoo.so è collegato dinamicamente al libpng14.so.14 (1.4.8) (EDIT 1)

libbar.so sembra essere staticamente collegato a una versione unknwon di libpng libpng 1.2.8 (EDIT 1)

dico "sembra essere", perché:

  • ldd libbar.so non mostra nulla di png
  • nm -D libbar.so | grep png_read_png dice "004f41b0 T png_read_png"
  • less libbar.so | grep png_read_png dice "4577: 004f41b0 738 FUNC globale predefinito 10 png_read_png"

all'avvio del programma, interruzione :

terminate called after throwing an instance of 'char const*' 

Questo è gdb backtrace:

#0 0xb7ffd424 in __kernel_vsyscall() 
#1 0xb5e776a1 in raise() from /lib/libc.so.6 
#2 0xb5e78de2 in abort() from /lib/libc.so.6 
#3 0xb60a997f in __gnu_cxx::__verbose_terminate_handler()() from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6 
#4 0xb60a78a5 in ??() from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6 
#5 0xb60a78e2 in std::terminate()() from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6 
#6 0xb60a7a21 in __cxa_throw() from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6 
#7 0xb5abf76d in ??() from /usr/lib/libfreeimage.so.3 
#8 0xb6fb9346 in png_error() from lib/libfsdk.so 
#9 0xb6fa2a59 in png_create_read_struct_2() from lib/libfsdk.so 
#10 0xb6fa2b7a in png_create_read_struct() from lib/libfsdk.so 
#11 0xb5abfa44 in ??() from /usr/lib/libfoo.so 
#12 0xb5aa766b in FreeImage_LoadFromHandle() from /usr/lib/libfreeimage.so.3 
#13 0xb5aa59f6 in FreeImage_LoadFromMemory() from /usr/lib/libfreeimage.so.3 
#14 0xb68a94a5 in Foo::Image::load (this=0xb4eff560, input=...) 

Come si può vedere, viene generata un'eccezione in Foo :: :: Immagine carico che appartengono alla libfoo.so

La disattivazione della parte del mio codice che utilizza libbar.so e la rimozione di collegamento ad esso, Foo :: Image :: load non lancia alcuna eccezione e funziona correttamente.

Quindi immagino che possa essere dovuto ad alcune ambiguità nella tabella dei simboli. Come posso ripararlo?

EDIT 1

png_access_version_number()

  • Con libbar.so legato, png_access_version_number() ritorno 10208: versione 1.2.8
  • Senza libbar.so legato, png_access_version_number() ritorno 10408: versione 1.4.8
+2

È necessario utilizzare 'nm -D' per esaminare i dynsyms di una libreria condivisa. Proprio 'nm' è per i simboli di debug, che sono spogliati nella maggior parte delle distro. –

+0

@ jørgensen, grazie! –

+0

Sto cercando di capire quale versione di libpng è collegata staticamente a * libbar.so * –

risposta

4

Poiché non è possibile ricostruire una delle librerie e poiché non è possibile consentire alle librerie di risiedere nello stesso "spazio dei nomi del linker dinamico" a causa di simboli in conflitto, l'unica scelta è isolare.

È possibile ottenere ciò utilizzando dlopen("lib*.so", RTLD_LOCAL) (per una o entrambe le librerie), anziché collegarsi direttamente a esse.

Questo potrebbe essere praticabile se hai solo bisogno di alcuni simboli, ad es.libfoo.so - puoi semplicemente usare dlsym invece di chiamare direttamente le funzioni.

Se si dispone di "troppe" dipendenze su entrambe le librerie, l'altra soluzione potrebbe essere quella di creare una libreria "interposer". Diciamo che vuoi interporre libbar.so, e hai bisogno di bar1(), bar2(), ... bar1000() da esso.

Write (o generare con un semplice script Perl) un file di origine che assomiglia a questo:

static void *handle; 
void *bar1() 
{ 
    static void* (*pfn)(void *arg1, void *arg2, void *arg3, ..., argN); 
    if (pfn == NULL) { 
     if (handle == NULL) 
     handle = dlopen("libbar.so", RTLD_LOCAL|RTLD_LAZY); 
     pfn = dlsym(handle, "bar1"); 
    } 
    return (*pfn)(arg1, arg2, ..., argN); 
} 
... repeat for all other libbar functions you depend on 

Ora compilare e collegare questa fonte in libbar_interposer.so e collegare l'applicazione nei suoi confronti (questo non funzionerà per C++ a causa del nome mangling, solo per plain- C). Voilà, nessuna fonte cambia all'applicazione, e hai ancora isolato libbar.so così i suoi simboli non saranno visibili al resto dell'applicazione, e in particolare non entrerà in conflitto con alcun simbolo in libpng.

+0

Vale la pena notare che si dovrebbe fare attenzione a non passare le strutture dati libpng tra libfoo e libbar se si esegue questa operazione. Inoltre, provare a ricostruire libbar per collegarsi dinamicamente a libpng se possibile. – bdonlan

+0

Grazie! Questo mi dà una speranza. La mia soluzione era quella di dividere la parte del programma usando libbar.so e scambiare dati con il programma principale attraverso la memoria condivisa. Ma questa soluzione sembra più elegante. –

+0

Ho usato la tua soluzione, ma con alcune modifiche: scrivendo alcune funzioni di "wrapper" in una nuova libreria "libbar_wrapper.so" e caricandola con 'dlopen' e' dlsym'. Ho bisogno di entrambe le bandiere 'RTLD_LOCAL | RTLD_LAZY'. E funziona! Risposta epica! –

Problemi correlati