2010-11-05 7 views
25

Considerate abbiamo la seguente situazione:Capire come dinamica di collegamento funziona su UNIX

  • un programma chiamato program che dipende in modo dinamico sulla libfoo.so
  • libfoo.so che dipende da niente (beh, dipende libstdc++ e roba del genere, ma Suppongo di poterlo omettere)

program funziona perfettamente.

Improvvisamente, le modifiche dei codici libfoo e alcune funzioni ora utilizzano internamente func_bar() una funzione fornita da un'altra libreria libbar.so.

libfoo.so viene ricompilato e ora dipende da libbar.so. program rimane invariato, ma dipende solo da libfoo.so.

Ora quando eseguo program si lamenta che non riesce a trovare func_bar().

Ecco le mie domande:

interfaccia
  • libfoo.so non ha cambiato, solo la sua attuazione. Perché lo program deve essere esplicitamente con libbar.so?
  • L'albero delle dipendenze non è ricorsivo? Avrei pensato che dal libfoo.so dipende da libbar.so, libbar.so sarebbe stato automaticamente aggiunto all'elenco delle dipendenze di program, senza la ricompilazione. Tuttavia, ldd program indica che non è il caso.

Sembra strano che uno deve ricompilazione (relink) ogni binario che dipende da alcuni ogni libreria che le dipendenze della biblioteca cambiano. Che soluzioni ho qui per impedirlo?

+0

Puoi pubblicare una configurazione minima che riproduce il problema? I commenti di vitaut che seguono il suo post sembrano descrivere lo stesso processo e non arrivano allo stesso problema. Forse se metti dei semplici passaggi, potremmo aiutarti a rispondere alla domanda? –

risposta

17

Il problema si verifica quando non si è collegato libfoo.so a libbar. Quando si compila un eseguibile, per impostazione predefinita il linker non ti consente di lasciare riferimenti indefiniti. Tuttavia, quando stai compilando una libreria condivisa, lo sarà e si aspetterà che siano soddisfatti al momento del collegamento. In questo modo, libfoo può utilizzare le funzioni esportate dallo stesso program - quando si tenta di eseguirlo, il linker dinamico si aspetta che lo func_bar() sia fornito da program. Il problema è illustrato in questo modo:

(foo.c è selfcontained)

export LD_RUN_PATH=`pwd` 
gcc -Wall -shared foo.c -o libfoo.so 
gcc -Wall -L. p.c -lfoo -o p 

A questo punto, ./p viene eseguito correttamente, come ci si aspetterebbe. Abbiamo quindi creare libbar.so e modifichiamo foo.c usarlo:

gcc -Wall -shared bar.c -o libbar.so 
gcc -Wall -shared foo.c -o libfoo.so 

A questo punto, ./p dà l'errore che si descrive. Se controlliamo ldd libfoo.so, notiamo che lo non è con una dipendenza su libbar.so - questo è l'errore. Per correggere l'errore, dobbiamo collegare libfoo.so correttamente:

gcc -Wall -L. -lbar -shared foo.c -o libfoo.so 

A questo punto, ./p corre ancora una volta in modo corretto, e ldd libfoo.so mostra una dipendenza libbar.so.

+0

Avevi ragione: non stavo collegando con 'libbar.so'. Funziona come un fascino ora! Grazie molto ! – ereOn

2

Non hai fornito alcuna informazione di sistema, stai usando glibc? Se sì qual è l'output di questo comando:

LD_DEBUG = Programmi

Controllare anche "How to write shared (ELF) libraries" (pdf) (se si sta utilizzando glibc o no)

1

Il vostro programma non dispone di collegamento con libbar.so.

Penso che il problema sia causato dal non riuscire a specificare libbar.so come dipendenza da libfoo.so quando si costruisce il successivo. io non sono sicuro di quello che sistema di compilazione stai usando ma in CMake si può fare come segue:

add_library(bar SHARED bar.c) 

add_library(foo SHARED foo.c) 
target_link_libraries(foo bar) 

add_executable(program program.c) 
target_link_libraries(program foo) 

Come si può vedere program è collegata solo con foo (libfoo.so) e foo solo con bar (libbar.so).

Oppure potrebbe non essere possibile trovare libbar.so. Prova a specificare il percorso della sua directory nella variabile di ambiente LD_LIBRARY_PATH.

+1

La domanda è cosa fa dietro le quinte di CMake, potrebbe essere abbastanza intelligente da creare il comando di collegamento giusto per il programma –

+0

@Peer Stritzinger: Buona domanda. Ci ho pensato e ho fatto alcuni esperimenti (costruendo 'program' mentre' foo' non aveva un link a 'bar', quindi costruendo' foo' e 'bar', ma non' program') e funzionava. Quindi la magia da parte di cmake sembra improbabile in questo caso, anche se in realtà è intelligente =). – vitaut

+1

Questo risponde veramente alla domanda? Ovviamente, il collegamento di 'libbar' con' libfoo' e * then * il collegamento con 'program' funzionerà, indipendentemente dal sistema di build. Tuttavia, se 'program' è collegato con' libfoo' e quindi 'libfoo' viene aggiornato per il collegamento con' libbar', questo potrebbe non essere il caso. Se il tuo script CMake, è chiaro che 'program' ricollega con' libfoo' se 'libfoo' cambia in collegamento con' libbar' senza alcuna magia. –

8

In Fedora il collegamento dinamico viene eseguito da ld-linux.so.2. Il linker dinamico usa /etc/ld.so.cache e /etc/ld.so.preload per trovare i file della libreria.

Eseguire ldconfig per indicare al sistema dove libfoo deve cercare libbar.

ldconfig cerca in/lib,/usr/lib e in qualsiasi directory elencata in /etc/ld.so.conf. Puoi controllare quali librerie un programma usa con ldd.

Ulteriori dettagli sono disponibili sulle pagine di manuale per ciascun comando.

Ecco un esempio di un'applicazione che utilizza le librerie condivise.
Program.cc

#include "foo.h" 
#include <iostream> 

int main(int argc, char *argv[]) 
{ 
    for (int i = 0; i < argc; ++i) { 
     std::cout << func_foo(argv[i]) << std::endl; 
    } 
} 

foo.h

#ifndef FOO_H 
#define FOO_H 
#include <string> 
std::string func_foo(std::string const &); 
#endif 

foo.cc

#include "foo.h" 

std::string func_foo(std::string const &arg) 
{ 
    return arg + "|" + __func__; 
} 

bar.h

#ifndef BAR_H 
#define BAR_H 
#include <string> 
std::string func_bar(); 
#endif 

bar.cc

#include "bar.h" 

std::string func_bar() 
{ 
    return __func__; 
} 

Costruire con libfoo.so come libreria condivisa.
g ++ -Wall -Wextra -fPIC -shared foo.cc -o libfoo.so
g ++ -lfoo -L./ -Wall -Wextra program.cc foo.h -o programma
programma ldd
...
libfoo.so => ​​non trovato

Aggiornamento /etc/ld.so.cache
sudo ldconfig/home/Tobias/progetti/stub/SO/

LDD mostra che il linker dinamico trova libfoo.so
programma ldd
...
libfoo.so => ​​/home/tobias/projects/stubs/so/libfoo.so (0x00007f0bb9f15000)

Aggiungere una chiamata a libbar.so in libfoo.so
Nuovo foo.cc

#include "foo.h" 
#include "bar.h" 

std::string func_foo(std::string const &arg) 
{ 
    return arg + "|" + __func__ + "|" + func_bar(); 
} 

Corporatura libbar.so e ricostruire libfoo.so
g ++ -Wall -Wextra -fPIC -shared bar.cc -o libbar.so
g ++ -Wall -Wextra -fPIC -shared libbar.so foo .cc -o libfoo.so
ldd libfoo.so
...
libbar.so => ​​non trovato

programma ldd
...
libfoo.so => ​​/home/tobias/projects/stubs/so/libfoo.so (0x00007f49236c7000)
libbar.so => ​​non trovato
Questo dimostra che il linker dinamico trova ancora libfoo.so ma non libbar. so
Ancora aggiornare /etc/ld.so.cache e ricontrollare.
sudo ldconfig/home/Tobias/progetti/stub/SO/
LDD libfoo.so
...
libbar.so => ​​/home/tobias/projects/stubs/so/libbar.so (0x00007f935e0bd000)

programma ldd
...
libfoo.so => ​​/home/tobias/projects/stubs/so/libfoo.so (0x00007f2be4f11000)
libbar.so => ​​/ home/Tobias/progetti/stubs/so/libbar.so (0x00007f2be4d0e000)

B si trovano libhoo.so e libbar.so.

Nota questo ultimo passaggio non ha alcun effetto sul programma applicativo. Se sei veramente rigido, ldconfig è una specie di ricollegamento. Strano o meno il linker deve conoscere le dipendenze delle librerie che collega. Ci sono molti altri modi per implementarlo ma questo è stato scelto.

+0

Grazie per l'informazione :) – ereOn

1

Questo non dovrebbe essere il caso, a meno che qualcosa circa il simbolo bar_func sia stato modificato. Usa il comando "nm" per ottenere un dump dei simboli sia nel tuo programma che nell'oggetto condiviso - vedi se c'è una mancata corrispondenza e perché.

+1

La mia lettura della domanda è che il cambiamento in 'bar_func()' è che in precedenza non era usato, ma ora è usato. –

Problemi correlati