Non riesci a trovare .so nella stessa directory dell'eseguibile?


45

Ho un eseguibile che deve collegarsi libtest.sodinamicamente, quindi li metto nella stessa directory, quindi:

cd path_to_dir
./binary

Ma ottenuto questo:

error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

Come può non essere in grado di trovare libtest.soquale si trova già nella stessa directory dell'eseguibile stesso?

Risposte:


25

Il caricatore non controlla mai la directory corrente per oggetti condivisi a meno che non sia esplicitamente indirizzato a via $LD_LIBRARY_PATH. Vedi la ld.so(8)pagina man per maggiori dettagli.


echo $LD_LIBRARY_PATHè vuoto sulla mia macchina :(
linuxer

Di solito lo è.
Ignacio Vazquez-Abrams,

2
Specifica ulteriori directory in cui il caricatore deve cercare le librerie.
Ignacio Vazquez-Abrams,

1
I percorsi in * nix sono separati da due punti ( :), non da un punto e virgola.
Ignacio Vazquez-Abrams,

3
LD_LIBRARY_PATH è generalmente una cattiva scelta in produzione. È utile per gli hack rapidi e cose come aiutare i binari disinstallati a trovare le loro librerie condivise durante l'esecuzione di unit test (think ./configure; make; make check). Quando costruisci il tuo binario, puoi mettere la tua libreria in una posizione standard (elencata in /etc/ld.so.conf) o passare il flag -R al linker per far sapere al binario dove cercare.
automatthias,

57

Mentre puoi impostare LD_LIBRARY_PATH per far sapere al linker dinamico dove cercare, ci sono opzioni migliori. Puoi mettere la tua libreria condivisa in uno dei posti standard, vedi /etc/ld.so.conf(su Linux) e /usr/bin/crle(su Solaris) per l'elenco di questi posti

È possibile passare -R <path>al linker durante la creazione del file binario, che verrà aggiunto <path>all'elenco delle directory scansionate per la libreria condivisa. Ecco un esempio Innanzitutto, mostrando il problema:

libtest.h:

void hello_world(void);

libtest.c:

#include <stdio.h>
void hello_world(void) {
  printf("Hello world, I'm a library!\n");
}

Ciao C:

#include "libtest.h"
int main(int argc, char **argv) {
  hello_world();
}

Makefile (le schede devono essere utilizzate):

all: hello
hello: libtest.so.0
%.o: %.c
        $(CC) $(CFLAGS) -fPIC -c -o $@ $<
libtest.so.0.0.1: libtest.o
        $(CC) -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
libtest.so.0: libtest.so.0.0.1
        ln -s $< $@
clean:
        rm -f hello libtest.o hello.o libtest.so.0.0.1 libtest.so.0

Eseguiamolo:

$ make
cc  -fPIC -c -o libtest.o libtest.c
cc -shared -Wl,-soname,libtest.so.0 -o libtest.so.0.0.1 libtest.o
ln -s libtest.so.0.0.1 libtest.so.0
cc     hello.c libtest.so.0   -o hello
$ ./hello 
./hello: error while loading shared libraries: libtest.so.0: cannot open shared object file: No such file or directory

Come sistemarlo? Aggiungi -R <path>ai flag del linker (qui, impostando LDFLAGS).

$ make clean
(...)
$ make LDFLAGS="-Wl,-R -Wl,/home/maciej/src/tmp"
(...)
cc   -Wl,-R -Wl,/home/maciej/src/tmp  hello.c libtest.so.0   -o hello
$ ./hello 
Hello world, I'm a library!

Guardando il binario, puoi vedere che ha bisogno di libtest.so.0:

$ objdump -p hello | grep NEEDED
  NEEDED               libtest.so.0
  NEEDED               libc.so.6

Il binario cercherà le sue librerie, oltre alle posizioni standard, nella directory specificata:

$ objdump -p hello | grep RPATH
  RPATH                /home/maciej/src/tmp

Se vuoi che il binario cerchi nella directory corrente, puoi impostare RPATH su $ORIGIN. Questo è un po 'complicato, perché è necessario assicurarsi che il simbolo del dollaro non sia interpretato da make. Ecco un modo per farlo:

$ make CFLAGS="-fPIC" LDFLAGS="-Wl,-rpath '-Wl,\$\$ORIGIN'"
$ objdump -p hello | grep RPATH
  RPATH                $ORIGIN
$ ./hello 
Hello world, I'm a library!

1
Se non si utilizza make, ad esempio quando si chiama manualmente g++, provare -Wl,-rpath='$ORIGIN'(notare le virgolette singole) per impedire l' $ORIGINespansione in una stringa vuota.
Morpork,

14

Per caricare gli oggetti condivisi dalla stessa directory del tuo eseguibile, esegui semplicemente:

$ LD_LIBRARY_PATH=. ./binary

Nota: non modificherà la variabile LD_LIBRARY_PATH del sistema. La modifica riguarda solo questa e solo questa esecuzione del tuo programma.


4

Per chiunque continui a lottare senza risposta, ne ho trovato uno anch'io con il seguente suggerimento:

Puoi provare ad aggiornare ld.so.cache usando: sudo ldconfig -v

Ha funzionato per me.


Ha funzionato anche per me.
Gioele

3

Per chiunque utilizzi CMake per la propria build, è possibile impostare CMAKE_EXE_LINKER_FLAGSquanto segue:

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath='$ORIGIN'")

Ciò propagherà correttamente i flag del linker per tutti i tipi di build (ad esempio, Debug, Release, ecc ...) per cercare prima i file .so nella directory di lavoro corrente.


0

Il linker dinamico deciderà dove cercare le librerie. Nel caso di Linux, il linker dinamico di solito è GNU ld.so(o un'alternativa che di solito si comporterà identica per motivi di compatibilità.

Per citazioni da Wikipedia:

Il linker dinamico della libreria GNU C cerca le librerie condivise nei seguenti percorsi:

  1. I percorsi (separati da due punti) nell'attributo DT_RPATHsezione dinamica del file binario se presente e l' DT_RUNPATHattributo non esiste.
  2. L'percorsi nella variabile ambientale (separata da due punti) LD_LIBRARY_PATH, a meno che l'eseguibile è un setuid/ setgidbinario, nel qual caso viene ignorato. LD_LIBRARY_PATHpuò essere sovrascritto chiamando il linker dinamico con l'opzione --library-path (es. /lib/ld-linux.so.2 --library-path $ HOME / mylibs myprogram).
  3. I percorsi (separati da due punti) nell'attributo della DT_RUNPATHsezione dinamica del file binario, se presente.
  4. Ricerca basata sul file di cache ldconfig (spesso situato in /etc/ld.so.cache) che contiene un elenco compilato di librerie candidate precedentemente trovate nel percorso della libreria aumentata (impostato da /etc/ld.so.conf). Se, tuttavia, il binario era collegato con l' -z nodefaultlibopzione linker, le librerie nei percorsi di libreria predefiniti vengono ignorate.
  5. Nel percorso predefinito attendibile /libe quindi /usr/lib. Se il binario è stato collegato con l'opzione -z nodefaultlib linker, questo passaggio viene ignorato.

Fonte: https://en.wikipedia.org/wiki/Rpath

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.