Stellen Sie sich das folgende Szenario vor:
- Shared Library libA.so, ohne Abhängigkeiten.
- Shared Library libB.so mit libA.so als Abhängigkeit.
Ich möchte eine Binärdatei kompilieren, die mit der libB verknüpft ist. Sollte ich die Binärdatei nur mit libB oder entweder mit libA verknüpfen?
Gibt es eine Möglichkeit, nur mit den direkten Abhängigkeiten zu verknüpfen und die Auflösung nicht aufgelöster Symbole aus den Abhängigkeiten zur Laufzeit zu ermöglichen?
Ich mache mir Sorgen darüber, dass sich die libB-Implementierung der Bibliothek in Zukunft ändern und andere Abhängigkeiten einführen könnte (z. B. libC, libD, libE). Werde ich damit Probleme haben?
Mit anderen Worten:
- libA-Dateien: a.cpp ah
- libB-Dateien: b.cpp bh
- Hauptprogrammdateien: main.cpp
Natürlich enthält b.cpp ah und main.cpp bh
Kompilierungsbefehle:
g++ -fPIC a.cpp -c
g++ -shared -o libA.so a.o
g++ -fPIC b.cpp -c -I.
g++ -shared -o libB.so b.o -L. -lA
Welche der folgenden Optionen sollte ich verwenden?
g++ main.cpp -o main -I. -L. -lB
oder
g++ main.cpp -o main -I. -L. -lB -lA
Ich konnte die erste Option nicht verwenden. Der Linker beschwert sich über die ungelösten Symbole aus der Bibliothek libA. Aber es klingt ein bisschen seltsam für mich.
Vielen Dank.
- Aktualisierte Kommentare:
Wenn ich die Binärdatei verknüpfe, versucht der Linker, alle Symbole aus der Haupt- und der libB aufzulösen. LibB hat jedoch undefinierte Symbole aus der libA. Deshalb beschwert sich der Linker darüber.
Deshalb muss ich mich auch mit der libA verbinden. Ich habe jedoch einen Weg gefunden, ungelöste Symbole aus gemeinsam genutzten Bibliotheken zu ignorieren. Sieht so aus, als ob ich die folgende Befehlszeile verwenden sollte, um das zu tun:
g++ main.cpp -o main -I. -L. -lB -Wl,-unresolved-symbols=ignore-in-shared-libs
Es sieht so aus, als ob es immer noch möglich ist, die -rpath
Option zu verwenden. Allerdings muss ich es etwas besser verstehen.
Kennt jemand mögliche Fallstricke bei der Verwendung der -Wl,-unresolved-symbols=ignore-in-shared-libs
Option?
- Aktualisierte Kommentare 2:
-rpath
sollte nicht für diesen Zweck verwendet werden. Es ist nützlich, zu erzwingen, dass eine Bibliothek in einem bestimmten Verzeichnis gefunden wird. Der -unresolved-symbol
Ansatz sieht viel besser aus.
Danke noch einmal.
quelle
Antworten:
Es sieht so aus, als wären Sie schon den größten Teil des Weges dorthin. Gut gemacht mit Ihrer Untersuchung. Mal sehen, ob ich helfen kann, das "Warum" dahinter zu klären.
Hier ist, was der Linker tut. Wenn Sie Ihre ausführbare Datei ('main' oben) verknüpfen, sind einige Symbole (Funktionen und andere Dinge) ungelöst. Es wird die Liste der folgenden Bibliotheken durchgesehen und versucht, ungelöste Symbole aufzulösen. Unterwegs stellt es fest, dass einige der Symbole von libB.so bereitgestellt werden, und stellt fest, dass sie jetzt von dieser Bibliothek aufgelöst werden.
Es wird jedoch auch festgestellt, dass einige dieser Symbole andere Symbole verwenden, die in Ihrer ausführbaren Datei noch nicht aufgelöst sind. Daher müssen diese nun auch aufgelöst werden. Ohne Verknüpfung mit libA.so wäre Ihre Bewerbung unvollständig. Sobald die Verknüpfung mit libA.so hergestellt ist, werden alle Symbole aufgelöst und die Verknüpfung ist abgeschlossen.
Wie Sie gesehen haben,
-unresolved-symbols-in-shared-libs
behebt die Verwendung von das Problem nicht. Es wird nur so verschoben, dass diese Symbole zur Laufzeit aufgelöst werden. Das ist es, wofür-rpath
: die Bibliotheken angegeben werden sollen, die zur Laufzeit durchsucht werden sollen. Wenn diese Symbole nicht aufgelöst werden können, kann Ihre App nicht gestartet werden.Es ist nicht einfach, Bibliotheksabhängigkeiten herauszufinden, da ein Symbol von mehr als einer Bibliothek bereitgestellt werden kann und durch Verknüpfung mit einer dieser Bibliotheken erfüllt werden kann.
Es gibt hier eine andere Beschreibung dieses Prozesses: Warum verursacht die Reihenfolge, in der Bibliotheken verknüpft sind, manchmal Fehler in GCC?
quelle
Für die dynamische Verknüpfung nur mit direkten Abhängigkeiten Sie können
-Wl,--as-needed
mit dem Hinzufügen von LIBS nach-Wl,--as-needed
:Zum Überprüfen der direkten Abhängigkeiten sollten Sie readelf anstelle von ldd verwenden, da ldd auch die indirekten Abhängigkeiten anzeigt.
$ readelf -d main | grep library 0x0000000000000001 (NEEDED) Shared library: [libB.so] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
ldd zeigt auch die indirekten Abhängigkeiten:
$ LD_LIBRARY_PATH=. ldd ./main linux-vdso.so.1 (0x00007fff13717000) libB.so => ./libB.so (0x00007fb6738ed000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb6734ea000) libA.so => ./libA.so (0x00007fb6732e8000) /lib64/ld-linux-x86-64.so.2 (0x00007fb673af0000)
Wenn Sie cmake verwenden , können Sie die folgenden Zeilen hinzufügen, um nur direkte Abhängigkeiten einzuschließen :
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_EXE_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed ${CMAKE_SHARED_LINKER_FLAGS}")
quelle
Eine andere Option ist zu verwenden
libtool
Wenn Sie den
g++
Aufruf ändernlibtool --mode=compile g++
, um den Quellcode zu kompilieren und dannlibtool --mode=link g++
die Anwendung aus zu erstellenlibB
,libA
wird diese automatisch verknüpft.quelle
Dies ist ein interessanter Beitrag - ich habe mir auch damit den Kopf geschlagen, aber ich denke, Sie verpassen hier einen Punkt.
Die Idee ist wie folgt, richtig?
Betrachten wir das weiter.
Jetzt wurden libB.so und libA.so wie oben beschrieben kompiliert. Danach wird die erste Option sollte funktionieren, das heißt:
Ich denke, dass Ihr Problem von der Tatsache herrührt, dass
in main.cpp verweisen Sie auch auf symA
Hab ich recht?
Wenn Sie in Ihrem Code ein Symbol verwenden, muss dieses Symbol in einer .so-Datei enthalten sein
Die gesamte Idee der Verweise auf gemeinsam genutzte Bibliotheken (dh das Erstellen von APIs) besteht darin, dass die Symbole in den tieferen Ebenen ausgeblendet werden (denken Sie an das Schälen von Zwiebeln) und nicht verwendet werden. .. dh beziehen Sie sich nicht auf symA in Ihrer main.cpp, sondern nur auf symB (und lassen Sie symB nur symA verweisen).
quelle