Wie wird die Präferenz des Bibliothekspfads angegeben?

91

Ich kompiliere ein C ++ - Programm mit g++und ld. Ich habe eine .soBibliothek, die ich beim Verknüpfen verwenden möchte. Es besteht jedoch eine Bibliothek mit dem gleichen Namen in /usr/local/lib, und ldist die Wahl , dass die Bibliothek über das, was ich direkt spezifizieren bin. Wie kann ich das beheben?

Für die folgenden Beispiele ist meine Bibliotheksdatei /my/dir/libfoo.so.0. Dinge, die ich ausprobiert habe und die nicht funktionieren:

  • Mein g ++ Befehl ist g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp
  • Hinzufügen /my/dirzum Anfang oder Ende meiner $PATHen`-Variablen
  • Hinzufügen /my/dir/libfoo.so.0als Argument zu g ++
Heinrich Schmetterling
quelle
1
Was andere libfoo.*Dateien vorhanden sind und wo - .sow / o .0, .aetc etc?
Alex Martelli

Antworten:

92

Fügen Sie den Pfad zu Ihrer neuen Bibliothek hinzu LD_LIBRARY_PATH(auf dem Mac hat sie einen etwas anderen Namen ...)

Ihre Lösung sollte mit den -L/my/dir -lfooOptionen arbeiten. Verwenden Sie zur Laufzeit LD_LIBRARY_PATH, um auf den Speicherort Ihrer Bibliothek zu verweisen.

Vorsicht bei der Verwendung von LD_LIBRARY_PATH - kurz (vom Link):

..implikationen ..:
Sicherheit : Denken Sie daran, dass die in LD_LIBRARY_PATH angegebenen Verzeichnisse vor (!) den Standardspeicherorten durchsucht werden? Auf diese Weise könnte eine böse Person Ihre Anwendung dazu bringen, eine Version einer gemeinsam genutzten Bibliothek zu laden, die schädlichen Code enthält! Dies ist ein Grund, warum ausführbare Dateien von setuid / setgid diese Variable vernachlässigen!
Performance: Der Linkloader muss alle angegebenen Verzeichnisse durchsuchen, bis er das Verzeichnis findet, in dem sich die gemeinsam genutzte Bibliothek befindet - für ALLE gemeinsam genutzten Bibliotheken ist die Anwendung verknüpft! Dies bedeutet viele Systemaufrufe von open (), die mit "ENOENT (keine solche Datei oder kein solches Verzeichnis)" fehlschlagen! Wenn der Pfad viele Verzeichnisse enthält, steigt die Anzahl der fehlgeschlagenen Aufrufe linear an. Dies können Sie an der Startzeit der Anwendung ablesen. Wenn sich einige (oder alle) Verzeichnisse in einer NFS-Umgebung befinden, kann die Startzeit Ihrer Anwendungen sehr lang werden - und das gesamte System verlangsamen!
Inkonsistenz: Dies ist das häufigste Problem. LD_LIBRARY_PATH zwingt eine Anwendung, eine gemeinsam genutzte Bibliothek zu laden, mit der sie nicht verknüpft war, und das ist höchstwahrscheinlich nicht mit der Originalversion kompatibel. Dies kann entweder sehr offensichtlich sein, dh die Anwendung stürzt ab, oder es kann zu falschen Ergebnissen führen, wenn die aufgenommene Bibliothek nicht ganz das tut, was die Originalversion getan hätte. Besonders letzteres ist manchmal schwer zu debuggen.

ODER

Verwenden Sie die Option rpath über gcc, um den Suchpfad für die Linker-Laufzeitbibliothek zu verknüpfen, anstatt im Standardverzeichnis zu suchen (Option gcc):

-Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)

Dies ist gut für eine vorübergehende Lösung. Linker durchsucht zuerst LD_LIBRARY_PATH nach Bibliotheken, bevor er in Standardverzeichnisse schaut.

Wenn Sie LD_LIBRARY_PATH nicht dauerhaft aktualisieren möchten, können Sie dies im laufenden Betrieb über die Befehlszeile tun:

LD_LIBRARY_PATH=/some/custom/dir ./fooo

Sie können überprüfen, was Bibliothekslinker über die Verwendung wissen (Beispiel):

/sbin/ldconfig -p | grep libpthread
        libpthread.so.0 (libc6, OS ABI: Linux 2.6.4) => /lib/libpthread.so.0

Und Sie können überprüfen, welche Bibliothek Ihre Anwendung verwendet:

ldd foo
        linux-gate.so.1 =>  (0xffffe000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb7f9e000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0xb7e6e000)
        librt.so.1 => /lib/librt.so.1 (0xb7e65000)
        libm.so.6 => /lib/libm.so.6 (0xb7d5b000)
        libc.so.6 => /lib/libc.so.6 (0xb7c2e000)
        /lib/ld-linux.so.2 (0xb7fc7000)
        libdl.so.2 => /lib/libdl.so.2 (0xb7c2a000)
        libz.so.1 => /lib/libz.so.1 (0xb7c18000)
stefanB
quelle
21
LD_LIBRARY_PATHwird zur Laufzeit gesucht, zur Kompilierungszeit, die Sie festlegen möchten LIBRARY_PATH. Siehe gcc.gnu.org/onlinedocs/gcc/Environment-Variables.html
Bjoern Dahlgren
1
Wenn sich Ihre Bibliothek vollständig von der Systembibliothek unterscheidet, dh immer verwendet wird, verwenden Sie bitte die rpath-Lösung. LD_LIBRARY_PATH ist ein Hack zum Testen und sollte nicht erforderlich sein, damit eine ausführbare Datei ordnungsgemäß funktioniert.
user2746401
1
sein DYLD_LIBRARY_PATH für Mac
cbinder
Hier ist ein vollständiger Beispielbefehl (für C), der basierend auf dieser Antwort funktioniert:gcc myFile.c -o myFile.o -l myLibraryBaseName -Wl,-rpath,locationOfMyLibrary -L locationOfMyLibrary
Jet Blue
24

Dies ist eine alte Frage, aber niemand scheint dies erwähnt zu haben.

Sie hatten Glück, dass das Ding überhaupt verknüpft war.

Du musstest dich ändern

g++ -g -Wall -o my_binary -L/my/dir -lfoo bar.cpp

dazu:

g++ -g -Wall -o my_binary -L/my/dir bar.cpp -lfoo

Ihr Linker verfolgt die Symbole, die aufgelöst werden müssen. Wenn die Bibliothek zuerst gelesen wird, sind keine Symbole erforderlich, daher werden die darin enthaltenen Symbole ignoriert. Geben Sie die Bibliotheken nach den Dingen an, die mit ihnen verknüpft werden müssen, damit Ihr Linker Symbole enthält.

Außerdem -lfoowird speziell nach einer Datei mit dem Namen libfoo.aoder libfoo.sonach Bedarf gesucht . Nicht libfoo.so.0. Also entweder lnden Namen oder die Bibliothek als entsprechend umbenennen.

So zitieren Sie die gcc-Manpage:

-l library
   ...
   It makes a difference where in the command you 
   write this option; the linker searches and processes 
   libraries and object files in the order they are 
   specified.  Thus, foo.o -lz bar.o searches library z 
   after file foo.o but before bar.o.  If bar.o refers 
   to functions in z, those functions may not be loaded.

Das direkte Hinzufügen der Datei zur g++Befehlszeile sollte funktionieren, es sei denn, Sie haben sie vorher angegeben bar.cpp, sodass der Linker sie ignoriert, weil keine erforderlichen Symbole vorhanden sind, da noch keine Symbole benötigt wurden.

Michael Speer
quelle
21

Die Angabe des absoluten Pfads zur Bibliothek sollte einwandfrei funktionieren:

g++ /my/dir/libfoo.so.0  ...

Haben Sie daran gedacht, den zu entfernen, -lfoonachdem Sie den absoluten Pfad hinzugefügt haben?

R Samuel Klatchko
quelle
1
Diese Lösung hat auch für mich gut funktioniert - ich habe versucht, eine Verknüpfung mit einer anderen Version von Qt5 als dem Distributionsentwicklungspaket herzustellen. Vielen Dank.
Wump
Wie funktioniert das für @versionierte Symbole? Minimales Beispiel: github.com/cirosantilli/cpp-cheat/blob/…
Ciro Santilli 法轮功 冠状 病 六四 事件 26
11

Alternativ können Sie die Umgebungsvariablen LIBRARY_PATHund verwenden CPLUS_INCLUDE_PATH, die jeweils angeben, wo nach Bibliotheken und wo nach Headern gesucht werden soll ( CPATHerledigt auch die Arbeit), ohne die Optionen -L und -I anzugeben.

Bearbeiten: CPATHEnthält einen Header mit -Iund CPLUS_INCLUDE_PATHmit -isystem.

Alexandre Hamez
quelle
Könnten Sie bitte ein Beispiel für die Verwendung hinzufügen?
Hanna Khalil
export LIBRARY_PATH = /path/to/libin der gleichen Konsolensitzung, in der Sie kompilieren
Alexandre Hamez
0

Wenn man mit DLL in Windows arbeitet und .so-Versionsnummern in Linux / QT überspringen möchte, werden durch Hinzufügen CONFIG += pluginVersionsnummern entfernt. Wie Herr Klatchko erwähnte, funktioniert es gut, den absoluten Pfad zu .so zu verwenden und ihn dem Linker zu geben.

Pekka Lehtikoski
quelle