PDA

View Full Version : creazione file oggetto (librerie dinamiche)


fracarro
20-02-2006, 09:49
c'è un modo per risolvere gli errori generati dalle librerie dinamiche quando si cerca di eseguire su una distribuzione di linux (A) un file eseguibile creato con un'altra distribuzione (B)? E' possibile magari creare un file oggetto su B che contenga tutte le librerie necessarie per far girare il programma e poi magari compilare solo l'oggetto su A? Grazie per l'aiuto.

-fidel-
20-02-2006, 10:38
c'è un modo per risolvere gli errori generati dalle librerie dinamiche quando si cerca di eseguire su una distribuzione di linux (A) un file eseguibile creato con un'altra distribuzione (B)?

Se l'eseguibile creato su (B) necessita di alcune librerie dinamiche, il programma può essere lanciato su un'altra distro (A) a patto che le librerie necessarie siano presenti (e mi sembra giusto :D). Ovviamente la versione delle librerie deve essere "compatibile" (stessa versione o superiore). Non è importante la posizione delle librerie in (A) e (B), dal momento che su Linux tramite il comando "ldconfig" si indica al linker del SO dove reperire le librerie (le cui directory sono specificate /etc/ld.so.conf). Tale comando viene lanciato automaticamente ogni volta che si installa una nuova libreria (a mano o con rpm) quindi non devi normalmente preoccuparti di farlo a mano, era solo per spiegare ;)

E' possibile magari creare un file oggetto su B che contenga tutte le librerie necessarie per far girare il programma e poi magari compilare solo l'oggetto su A? Grazie per l'aiuto.

?? Mi sembra un'idea bizzarra ;) Al peggio compili tutto in modo statico, così da "inglobare" le librerie richieste nell'eseguibile (esso diventa più grosso in termini di spazio occupato su disco, ma non ti crea problemi di dipendenze) - esempio di programma compilato in modo statico è Firefox se non erro.
Tornando alla tua idea, non ti pare più semplice installare le librerie richieste dal programma anche su (A), se su questo sistema non sono presenti? ;)

fracarro
21-02-2006, 16:08
Il problema è che il codice compilato con le librerie di A mi da degli ottimi risultati. Lo stesso codice compilato su macchine con un compilatore differente (superiore) anche con la stessa distribuzione mi da risultati peggiori (il che di per se sembra assurdo, magari la gestione dei numeri casuali cambia il comportamento dell'algoritmo). Quindi per risolvere il problema l'idea è di creare un eseguibile in cui includere tutte le librerie che gli piacciono tanto ( per la cronaca lavoro sulla suse 9) per far si che il codice eseguito poi su qualsiasi distribuzione si comporti sempre allo stesso modo. A tal fine la tua idea di compilare tutto in modo statico mi sembra la soluzione ai miei problemi. come si fa? e soprattutto come faccio a sapere quali sono le librerie dinamiche eventualmente da linkare nell'eseguibile? Grazie per l'aiuto fidel.

ilsensine
21-02-2006, 16:17
Ci sono diversi modi per risolvere il problema, non solo la compilazione statica.

Un modo potrebbe essere di decidere una directory di installazione per il tuo programma (ad es. /opt/myprog), e portarsi dietro le librerie dinamiche necessarie. Quindi l'eseguibile deve essere linkato in modo da cercare in primis nella directory di installazione (si fa con -Wl,--rpath=/opt/myprog).

Altre soluzioni passano per LD_LIBRARY_PATH, LD_PRELOAD, ecc. (oltre al link statico).

-fidel-
21-02-2006, 17:47
Ci sono diversi modi per risolvere il problema, non solo la compilazione statica.

Un modo potrebbe essere di decidere una directory di installazione per il tuo programma (ad es. /opt/myprog), e portarsi dietro le librerie dinamiche necessarie. Quindi l'eseguibile deve essere linkato in modo da cercare in primis nella directory di installazione (si fa con -Wl,--rpath=/opt/myprog).

Altre soluzioni passano per LD_LIBRARY_PATH, LD_PRELOAD, ecc. (oltre al link statico).

Domanda: voglio che il mio programma carichi a runtime le librerie presenti nella cartella stessa del programma (es. /opt/myprog) invece che in quelle di default, e non voglio specificare questo a compile time. Sfruttando la variabile d'ambiente LD_LIBRARY_PATH ed ldconfig (aggiungendo /opt/myprog in /etc/ld.so.conf) risolvo no? In altre parole, LD_LIBRARY_PATH specifica anche la precedenza delle directory in cui il linker andrà a cercare le librerie?

I passi che eseguirei sono quindi:
1) modifica della variabile d'ambiente LD_LIBRARY_PATH in modo tale che la prima directory elencata sia /opt/myprog
2) lancio "ldconfig -n /opt/myprog" (oppure aggiungo /opt/myprog in /etc/ld.so.conf e lancio semplicemente "ldconfig"

(questo ovviamente può essere fatto automaticamente nella fase "post" di un'installazione da rpm)

-fidel-
21-02-2006, 17:57
Il problema è che il codice compilato con le librerie di A mi da degli ottimi risultati. Lo stesso codice compilato su macchine con un compilatore differente (superiore) anche con la stessa distribuzione mi da risultati peggiori (il che di per se sembra assurdo, magari la gestione dei numeri casuali cambia il comportamento dell'algoritmo). Quindi per risolvere il problema l'idea è di creare un eseguibile in cui includere tutte le librerie che gli piacciono tanto ( per la cronaca lavoro sulla suse 9) per far si che il codice eseguito poi su qualsiasi distribuzione si comporti sempre allo stesso modo. A tal fine la tua idea di compilare tutto in modo statico mi sembra la soluzione ai miei problemi. come si fa? e soprattutto come faccio a sapere quali sono le librerie dinamiche eventualmente da linkare nell'eseguibile? Grazie per l'aiuto fidel.

Per compilare in modo statico hai bisogno di:

1) i sorgenti delle librerie che il programma usa (se stai usando librerie installate tramite rpm ti basta avere normalmente il pacchetto -devel corrispondente per ciascuna libreria. L'unica eccezione che ricordo sono le librerie Qt, che ha due pacchetti diversi, il -devel che contiene solo gli header, ed il -devel-static che appunto contiene anche i sorgenti per eseguire una compilazione statica). Se qualcosa fallisce, installa la libreria compilandola dai sorgenti e stai tranquillo, ma con i pacchetti -devel personalmente non ho avuto mai dispiaceri.
2) passare al gcc l'opzione --static

Quindi è molto semplice, anche se avrai poi un eseguibile di dimensioni più ampie (in proporzione alla dimensione delle librerie).

Dimenticavo, per conoscere QUALI librerie il programma usa, devi lanciare il comando

ldd nome_eseguibile

sul programma linkato dinamicamente. Ti consiglio però se non vuoi impazzire (nel caso vuoi compilare staticamente programmi tipo amarok...) di andare sul sito web dell'applicazione e vedere da lì le dipendenze richieste. Devi necessariamente avere le mandatory dependencies (senza quelle librerie il programma non compila) ed a tua discrezione le librerie opzionali a seconda delle funzionalità aggiuntive che vuoi avere.

EDIT 1: Ah, se vuoi compilare staticamente programmi che sono forniti del file configure (quelli che compili con ./configure && make && make install per intenderci, in pratica tutti) e quindi non controlli direttamente il gcc, invece di quello che ho detto al punto 2), lanci semplicemente
./configure --enable-static
così che il make compilerà le librerie in modo statico.
Normalmente l'opzione --enable-static di configure ti permette anche di specificare QUALI librerie compilare staticamente e quali no (se non specifichi nulla, il make tenterà di compilare staticamente tutte le librerie richieste).

EDIT 2: Poi non ho capito una cosa:
Il problema è che il codice compilato con le librerie di A mi da degli ottimi risultati. Lo stesso codice compilato su macchine con un compilatore differente (superiore) anche con la stessa distribuzione mi da risultati peggiori
Compili sulla macchina A un programma, lo esegui su una macchina B che ha tutte le librerie necessarie, e ti gira peggio? Mi pareva stessi parlando solo di reperimento librerie (che tra l'altro non è un problema se le librerie sono già installate sul sistema B, il loader delle librerie dinamiche le trova tranquillamente dal momento che sulle distro il tutto è già ben settato senza intervento dell'utente): poi è sempre bello sapere come funziona il tutto.
Ho visto persone che "giocavano" con gli eseguibili linkati dinamicamente senza sapere neanche l'esistenza di ldconfig su suse ;)

-fidel-
21-02-2006, 18:12
Dimenticavo:

Un modo potrebbe essere di decidere una directory di installazione per il tuo programma (ad es. /opt/myprog), e portarsi dietro le librerie dinamiche necessarie. Quindi l'eseguibile deve essere linkato in modo da cercare in primis nella directory di installazione (si fa con -Wl,--rpath=/opt/myprog).

Questo è un ottimo metodo in alternativa alla compilazione statica, molto "windows like" (ops mi è sfuggito ;)): come pero' succede con Windows (ma anche con la compilazione statica), il pacchetto di installazione ti diventa in media 8-10 volte più grosso, però effettivamente non hai più problemi di dipendenze (cosa che un po' fa dannare gli utenti linux alle prime armi, vista la mole e la velocità di uscita di nuove release delle librerie in ambiente linux).

ilsensine
22-02-2006, 08:27
Domanda: voglio che il mio programma carichi a runtime le librerie presenti nella cartella stessa del programma (es. /opt/myprog) invece che in quelle di default, e non voglio specificare questo a compile time. Sfruttando la variabile d'ambiente LD_LIBRARY_PATH ed ldconfig (aggiungendo /opt/myprog in /etc/ld.so.conf) risolvo no? In altre parole, LD_LIBRARY_PATH specifica anche la precedenza delle directory in cui il linker andrà a cercare le librerie?
Sì, ha la precedenza sui path di sistema.
Nota che non è necessario utilizzare ld.so.conf, basta LD_LIBRARY_PATH.

(questo ovviamente può essere fatto automaticamente nella fase "post" di un'installazione da rpm)
E' come fanno diversi programmi, in effetti: l'eseguibile vero e proprio viene lanciato da uno script apposito che imposta le opportune variabili d'ambiente (tra cui LD_LIBRARY_PATH).
Nota che puoi anche usare --rpath per specificare una directory relativa (ad es. ../my/lib), ma è relativa alla directory di lancio del programma e non a quella in cui risiede il programma. Anche qui, occorre uno script che modifichi la directory corrente con quella del programma affinché --rpath abbia l'effetto desiderato.

-fidel-
22-02-2006, 09:33
Nota che non è necessario utilizzare ld.so.conf, basta LD_LIBRARY_PATH.

Ah quindi con LD_LIBRARY_PATH posso evitare di lanciare ldconfig... In effetti, rileggendo la pagina di man di ldconfig, mi sembra ora più un helper per ldd che altro. Non mi sembra necessario per cercare le librerie, sembra che serva solo per ottimizzare il caricamento delle librerie dinamiche. Mi sbaglio?


Nota che puoi anche usare --rpath per specificare una directory relativa (ad es. ../my/lib), ma è relativa alla directory di lancio del programma e non a quella in cui risiede il programma. Anche qui, occorre uno script che modifichi la directory corrente con quella del programma affinché --rpath abbia l'effetto desiderato.

Stai dicendo che, specificando un percorso relativo, se il programma risiede ad esempio in /opt/programmi e viene lanciato ad esempio da /home/pippo con il comando /opt/programmi/myprog, le librerie verrano prima cercate (rifacendomi al tuo esempio) in /home/my/lib ?

ilsensine
22-02-2006, 10:09
Ah quindi con LD_LIBRARY_PATH posso evitare di lanciare ldconfig... In effetti, rileggendo la pagina di man di ldconfig, mi sembra ora più un helper per ldd che altro. Non mi sembra necessario per cercare le librerie, sembra che serva solo per ottimizzare il caricamento delle librerie dinamiche. Mi sbaglio?
Non solo, ld.so.conf indica quali sono i path aggiuntivi alle librerie di sistema.
Su alcuni programmi il trucco di LD_LIBRARY_PATH o LD_PRELOAD non può funzionare per ovvi motivi di sicurezza (ad es. per i programmi suid).

Stai dicendo che, specificando un percorso relativo, se il programma risiede ad esempio in /opt/programmi e viene lanciato ad esempio da /home/pippo con il comando /opt/programmi/myprog, le librerie verrano prima cercate (rifacendomi al tuo esempio) in /home/my/lib ?
Esatto!

-fidel-
22-02-2006, 10:12
Non solo, ld.so.conf indica quali sono i path aggiuntivi alle librerie di sistema.
Su alcuni programmi il trucco di LD_LIBRARY_PATH o LD_PRELOAD non può funzionare per ovvi motivi di sicurezza (ad es. per i programmi suid).

Grazie per la delucidazione.


Esatto!

Buono a sapersi ;) Con il "metodo" --rpath meglio creare un piccolo script allora...