Sie finden .so nicht im selben Verzeichnis wie die ausführbare Datei?

45

Ich habe eine ausführbare Datei, mit der eine libtest.sodynamische Verknüpfung hergestellt werden muss. Deshalb lege ich sie in dasselbe Verzeichnis:

cd path_to_dir
./binary

Habe aber folgendes:

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

Wie kann es sein, dass es nicht findet, libtest.sowelches sich bereits im selben Verzeichnis wie die ausführbare Datei befindet?

Linuxer
quelle

Antworten:

25

Der Loader überprüft niemals das aktuelle Verzeichnis auf freigegebene Objekte, es sei denn, es wird ausdrücklich auf via verwiesen $LD_LIBRARY_PATH. ld.so(8)Weitere Informationen finden Sie auf der Manpage.

Ignacio Vazquez-Abrams
quelle
echo $LD_LIBRARY_PATHist auf meinem Rechner leer :(
Linuxer
Es ist normalerweise so.
Ignacio Vazquez-Abrams
2
Es gibt zusätzliche Verzeichnisse an, in denen der Loader nach Bibliotheken suchen soll.
Ignacio Vazquez-Abrams
1
Pfade in * nix werden durch einen Doppelpunkt ( :) und nicht durch ein Semikolon getrennt.
Ignacio Vazquez-Abrams
3
LD_LIBRARY_PATH ist im Allgemeinen eine schlechte Wahl in der Produktion. Es ist gut für schnelle Hacks und Dinge wie die Unterstützung von deinstallierten Binärdateien beim Auffinden ihrer gemeinsam genutzten Bibliotheken beim Ausführen von Komponententests (denke ./configure; make; make check). Wenn Sie Ihre Binärdatei erstellen, können Sie Ihre Bibliothek entweder an einem Standardspeicherort ablegen (aufgeführt unter /etc/ld.so.conf) oder das Flag -R an den Linker übergeben, um der Binärdatei mitzuteilen, wo sie suchen soll.
automatthias
57

Sie können LD_LIBRARY_PATH so einstellen, dass der dynamische Linker weiß, wo er suchen muss. Es gibt jedoch bessere Optionen. Sie können Ihre gemeinsam genutzte Bibliothek an einem der Standardorte ablegen. Eine Liste dieser Orte finden Sie unter /etc/ld.so.conf(Linux) und /usr/bin/crle(Solaris)

Sie können -R <path>beim Erstellen Ihrer Binärdatei an den Linker übergeben, der <path>der Liste der für Ihre gemeinsam genutzte Bibliothek durchsuchten Verzeichnisse hinzugefügt wird . Hier ist ein Beispiel. Zeigen Sie zunächst das Problem:

libtest.h:

void hello_world(void);

libtest.c:

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

Hallo c:

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

Makefile (Tabs müssen verwendet werden):

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

Lass es uns machen:

$ 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

Wie man es repariert? Fügen Sie -R <path>den Linker-Flags hinzu (hier durch Einstellen 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!

Wenn Sie sich die Binärdatei ansehen, sehen Sie, dass sie Folgendes benötigt libtest.so.0:

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

Die Binärdatei sucht, abgesehen von den Standardverzeichnissen, im angegebenen Verzeichnis nach ihren Bibliotheken:

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

Wenn die Binärdatei im aktuellen Verzeichnis angezeigt werden soll, können Sie den RPATH auf festlegen $ORIGIN. Dies ist etwas knifflig, da Sie sicherstellen müssen, dass das Dollarzeichen nicht von make interpretiert wird. Hier ist eine Möglichkeit, dies zu tun:

$ make CFLAGS="-fPIC" LDFLAGS="-Wl,-rpath '-Wl,\$\$ORIGIN'"
$ objdump -p hello | grep RPATH
  RPATH                $ORIGIN
$ ./hello 
Hello world, I'm a library!
automatisch
quelle
1
Wenn Sie dies nicht verwenden make, z. B. beim manuellen Aufrufen g++, versuchen Sie -Wl,-rpath='$ORIGIN'(beachten Sie die einfachen Anführungszeichen), zu verhindern, dass $ORIGINeine leere Zeichenfolge angezeigt wird.
Morpork
14

Um die freigegebenen Objekte aus demselben Verzeichnis wie Ihre ausführbare Datei zu laden, führen Sie einfach Folgendes aus:

$ LD_LIBRARY_PATH=. ./binary

Anmerkung: Die Variable LD_LIBRARY_PATH Ihres Systems wird nicht geändert. Die Änderung betrifft nur diese und nur diese Ausführung Ihres Programms.

Schwäne
quelle
4

Für alle, die noch keine Antwort haben, habe ich selbst einen mit folgendem Vorschlag gefunden:

Sie können versuchen, den ld.so.cache zu aktualisieren, indem Sie Folgendes verwenden: sudo ldconfig -v

Hat für mich gearbeitet.

Ian Frisbie
quelle
Arbeitete auch für mich.
Joel
3

Für alle Benutzer , die CMake für ihren Build verwenden, können Sie CMAKE_EXE_LINKER_FLAGSFolgendes festlegen :

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

Dadurch werden die Linker-Flags für alle Build-Typen (z. B. Debug, Release usw.) ordnungsgemäß weitergegeben, sodass zuerst im aktuellen Arbeitsverzeichnis nach .so-Dateien gesucht wird.

Michael Goldshteyn
quelle
0

Der dynamische Linker entscheidet, wo nach Bibliotheken gesucht wird. Im Falle von Linux ist der dynamische Linker normalerweise GNU ld.so(oder eine Alternative, die sich aus Kompatibilitätsgründen normalerweise identisch verhält).

Zitate aus der Wikipedia:

Der dynamische Linker der GNU C-Bibliothek sucht an folgenden Stellen nach gemeinsam genutzten Bibliotheken:

  1. Die (durch Doppelpunkte getrennten) Pfade im DT_RPATHdynamischen Abschnittsattribut der Binärdatei, falls vorhanden und das DT_RUNPATHAttribut nicht vorhanden.
  2. Die (durch Doppelpunkte getrennten) Pfade in der Umgebungsvariablen LD_LIBRARY_PATH, sofern die ausführbare Datei kein setuid/ setgidbinary ist. In diesem Fall wird sie ignoriert. LD_LIBRARY_PATHkann durch Aufruf des Dynamic Linker mit der Option --library-path (zB /lib/ld-linux.so.2 --library-path $ HOME / mylibs myprogram) überschrieben werden.
  3. Die (durch Doppelpunkte getrennten) Pfade im DT_RUNPATHdynamischen Abschnittsattribut der Binärdatei, falls vorhanden.
  4. Suche basierend auf der ldconfig-Cache-Datei (häufig unter /etc/ld.so.cache), die eine kompilierte Liste der Kandidatenbibliotheken enthält, die zuvor im erweiterten Bibliothekspfad (festgelegt durch /etc/ld.so.conf) gefunden wurden. Wenn die Binärdatei jedoch mit der -z nodefaultlibLinker-Option verknüpft wurde , werden Bibliotheken in den Standardbibliothekspfaden übersprungen.
  5. Im vertrauenswürdigen Standardpfad /libund dann /usr/lib. Wenn die Binärdatei mit der Linkeroption -z nodefaultlib verknüpft wurde, wird dieser Schritt übersprungen.

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

Mecki
quelle