Ich muss eine C ++ - Anwendung, die auf Ubuntu 12.10 mit libstdc ++ von GCC 4.7 basiert, auf Systemen bereitstellen, auf denen Ubuntu 10.04 ausgeführt wird, das mit einer erheblich älteren Version von libstdc ++ geliefert wird.
Derzeit kompiliere ich mit -static-libstdc++ -static-libgcc
, wie in diesem Blog-Beitrag vorgeschlagen: libstdc ++ statisch verknüpfen . Der Autor warnt davor, beim statischen Kompilieren von libstdc ++ dynamisch geladenen C ++ - Code zu verwenden, was ich noch nicht überprüft habe. Trotzdem scheint alles reibungslos zu laufen: Ich kann C ++ 11-Funktionen unter Ubuntu 10.04 nutzen, was ich auch wollte.
Ich stelle fest, dass dieser Artikel aus dem Jahr 2005 stammt und sich seitdem möglicherweise viel geändert hat. Ist der Rat noch aktuell? Gibt es irgendwelche lauernden Probleme, die ich beachten sollte?
-static-libstdc++
Option keinen Sinn . Sie würden sie einfach verwenden-static
kernel too old
in einem Ubuntu 1404-System einen Fehler erhalten. Die glibc.so ist wiekernel32.dll
im Fenster, sie ist Teil der Betriebssystemschnittstelle, wir sollten sie nicht in unsere Binärdatei einbetten. Sie können verwenden, umobjdump -T [binary path]
zu sehen, ob es dynamisch geladen istlibstdc++.so
oder nicht. Für Golang-Programmierer können Sie#cgo linux LDFLAGS: -static-libstdc++ -static-libgcc
vor dem Import "C"Antworten:
Dieser Blog-Beitrag ist ziemlich ungenau.
Nicht wahr. Die einzigen seit GCC 3.4 eingeführten C ++ ABI-Änderungen waren abwärtskompatibel, was bedeutet, dass der C ++ ABI seit fast neun Jahren stabil ist.
Die Unterschiede zwischen den gepatchten Versionen von GCC für Distributionen sind gering und ändern sich nicht an ABI. ZB Fedoras 4.6.3 20120306 (Red Hat 4.6.3-2) ist ABI-kompatibel mit den vorgelagerten FSF 4.6.x-Versionen und mit ziemlicher Sicherheit mit allen 4.6. x von jeder anderen Distribution.
Unter GNU / Linux verwenden die Laufzeitbibliotheken von GCC die ELF-Symbolversionierung, sodass Sie die von Objekten und Bibliotheken benötigten Symbolversionen leicht überprüfen können. Wenn Sie eine haben
libstdc++.so
, die diese Symbole bereitstellt, funktioniert dies, spielt es keine Rolle, ob es sich um eine etwas andere gepatchte Version handelt von einer anderen Version Ihrer Distribution.Dies ist auch nicht wahr.
Das statische Verknüpfen mit
libstdc++.a
ist jedoch eine Option für Sie.Der Grund, warum es möglicherweise nicht funktioniert, wenn Sie eine Bibliothek dynamisch laden (mit
dlopen
), ist, dass libstdc ++ - Symbole, von denen es abhängt, von Ihrer Anwendung möglicherweise nicht benötigt wurden, als Sie sie (statisch) verknüpft haben, sodass diese Symbole in Ihrer ausführbaren Datei nicht vorhanden sind. Dies kann durch dynamisches Verknüpfen der gemeinsam genutzten Bibliothek mitlibstdc++.so
(was ohnehin das Richtige ist, wenn es davon abhängt) gelöst werden . ELF-Symbol-Interposition bedeutet, dass Symbole, die in Ihrer ausführbaren Datei vorhanden sind, von der gemeinsam genutzten Bibliothek verwendet werden, andere jedoch nicht Das in Ihrer ausführbaren Datei vorhandene Element befindet sich in demlibstdc++.so
Link, auf den es verweist. Wenn Ihre Anwendung nicht verwendet wird, müssendlopen
Sie sich nicht darum kümmern.Eine andere Option (und die, die ich bevorzuge) besteht darin, die neuere
libstdc++.so
neben Ihrer Anwendung bereitzustellen und sicherzustellen, dass sie vor dem Standardsystem gefunden wird. Dieslibstdc++.so
kann erreicht werden, indem der dynamische Linker gezwungen wird, an der richtigen Stelle zu suchen, entweder mithilfe der$LD_LIBRARY_PATH
Umgebungsvariablen bei run-. Zeit oder durch Festlegen einerRPATH
in der ausführbaren Datei zur Verbindungszeit. Ich bevorzuge die Verwendung,RPATH
da dies nicht davon abhängt, dass die Umgebung richtig eingestellt ist, damit die Anwendung funktioniert. Wenn Sie mit Ihrer Anwendung verknüpfen'-Wl,-rpath,$ORIGIN'
( man beachte die einfachen Anführungszeichen um die Schale zu verhindern versuchen , zu erweitern$ORIGIN
) die ausführbare Datei wird dann eine hatRPATH
von$ORIGIN
denen erzählt die dynamischen Linker Look für gemeinsam genutzte Bibliotheken im selben Verzeichnis wie die ausführbaren Datei selbst. Wenn Sie die neuere setzenlibstdc++.so
Im selben Verzeichnis wie die ausführbare Datei befindet sie sich zur Laufzeit. Das Problem wurde behoben. (Eine andere Möglichkeit besteht darin, die ausführbare Datei in/some/path/bin/
und die neuere libstdc ++ einzufügen. Also in/some/path/lib/
und mit'-Wl,-rpath,$ORIGIN/../lib'
einem anderen festen Speicherort in Bezug auf die ausführbare Datei zu verknüpfen und den RPATH in Bezug auf zu setzen.$ORIGIN
)quelle
libstdc++.so.6
Symlink enthält, der bei der Installation so eingestellt ist, dass er auf die mitgelieferte Bibliothek oder auf die Systembibliothek verweist, wenn diese neuer ist. Es gibt kompliziertere Modelle mit gemischten Verknüpfungen, wie sie von Red Hat DTS verwendet werden, aber sie sind schwer selbst zu erstellen.Eine Ergänzung zu Jonathan Wakelys hervorragender Antwort, warum dlopen () problematisch ist:
Aufgrund des neuen Ausnahmebehandlungspools in GCC 5 (siehe PR 64535 und PR 65434 ) tritt jedes Mal ein Speicherverlust (des Poolobjekts ) auf, wenn Sie eine Bibliothek öffnen und schließen, die statisch mit libstdc ++ verknüpft ist. Wenn es also eine Chance gibt, dass Sie jemals dlopen verwenden, scheint es eine wirklich schlechte Idee zu sein, libstdc ++ statisch zu verknüpfen. Beachten Sie, dass dies ein echtes Leck ist, im Gegensatz zu dem in PR 65434 erwähnten gutartigen .
quelle
__gnu_cxx::__freeres()
scheint zumindest einige Hilfe bei diesem Problem zu bieten, da sie den internen Puffer des Poolobjekts freigibt. Für mich ist jedoch ziemlich unklar, welche Auswirkungen ein Aufruf dieser Funktion auf Ausnahmen hat, die versehentlich danach ausgelöst wurden.Möglicherweise müssen Sie auch sicherstellen, dass Sie nicht vom dynamischen glibc abhängig sind. Führen
ldd
Sie die resultierende ausführbare Datei aus und notieren Sie sich alle dynamischen Abhängigkeiten (libc / libm / libpthread sind übliche Verdächtige).Eine zusätzliche Übung wäre, eine Reihe von beteiligten C ++ 11-Beispielen mit dieser Methode zu erstellen und die resultierenden Binärdateien tatsächlich auf einem echten 10.04-System auszuprobieren. In den meisten Fällen wissen Sie sofort, ob das Programm funktioniert oder abstürzt, es sei denn, Sie tun etwas Seltsames mit dynamischem Laden.
quelle
printf
), aber solange das glibc unter Ubuntu 10.04 alle Funktionen bietet, die von dem neueren libstdc ++ benötigt werden, gibt es kein Problem damit, abhängig vom dynamischen glibc, niemals zu verlinken statisch zu glibcAdd-on zu Jonathan Wakelys Antwort bezüglich des RPATH:
RPATH funktioniert nur, wenn das betreffende RPATH das RPATH der laufenden Anwendung ist . Wenn Sie über eine Bibliothek verfügen, die über ein eigenes RPATH dynamisch mit einer Bibliothek verknüpft ist, wird das RPATH der Bibliothek vom RPATH der Anwendung überschrieben, die es lädt. Dies ist ein Problem, wenn Sie nicht garantieren können, dass der RPATH der Anwendung mit dem Ihrer Bibliothek identisch ist, z. B. wenn Sie erwarten, dass sich Ihre Abhängigkeiten in einem bestimmten Verzeichnis befinden, dieses Verzeichnis jedoch nicht Teil des RPATH der Anwendung ist.
Angenommen, Sie haben eine Anwendung App.exe, die eine dynamisch verknüpfte Abhängigkeit von libstdc ++. So.x für GCC 4.9 aufweist. Die App.exe hat diese Abhängigkeit durch das RPATH aufgelöst, dh
Angenommen, es gibt eine weitere Bibliothek Dependency.so, die eine dynamisch verknüpfte Abhängigkeit von libstdc ++. So.y für GCC 5.5 aufweist. Die Abhängigkeit wird hier durch das RPATH der Bibliothek aufgelöst, dh
Wenn App.exe Dependency.so lädt, wird das RPATH der Bibliothek weder angehängt noch vorangestellt . Es konsultiert es überhaupt nicht. Das einzige RPATH, das berücksichtigt wird, ist das der laufenden Anwendung oder in diesem Beispiel App.exe. Das heißt, wenn die Bibliothek auf Symbolen basiert, die sich in gcc5_5 / libstdc ++. So.y, aber nicht in gcc4_9 / libstdc ++. So.x befinden, kann die Bibliothek nicht geladen werden.
Dies ist nur ein Wort der Warnung, da ich in der Vergangenheit selbst auf diese Probleme gestoßen bin. RPATH ist ein sehr nützliches Tool, aber seine Implementierung hat noch einige Fallstricke.
quelle
Ich möchte Jonathan Wakelys Antwort Folgendes hinzufügen.
Herumspielen
-static-libstdc++
auf Linux, habe ich das Problem mit konfrontiertdlclose()
. Angenommen, wir haben eine statisch verknüpfte Anwendung 'A', die zur Laufzeitlibstdc++
dynamisch mit demlibstdc++
Plugin 'P' verknüpft geladen wird. Das ist gut. Wenn 'A' jedoch 'P' entlädt, tritt ein Segmentierungsfehler auf. Ich gehe davon auslibstdc++.so
, dass 'A' nach dem Entladen keine Symbole mehr verwenden kann, die sich auf beziehenlibstdc++
. Beachten Sie, dasslibstdc++
das Problem nicht auftritt , wenn sowohl 'A' als auch 'P' statisch verknüpft sind oder wenn 'A' dynamisch und 'P' statisch verknüpft sind.Zusammenfassung: Wenn Ihre Anwendung Plugins lädt / entlädt, mit denen möglicherweise eine dynamische Verknüpfung hergestellt wird,
libstdc++
muss die App auch dynamisch mit ihr verknüpft werden. Dies ist nur meine Beobachtung und ich würde gerne Ihre Kommentare erhalten.quelle
sbrk
) bestimmte Annahmen trifft und ziemlich erwartet, innerhalb eines Prozesses allein zu sein ... nicht sicher, ob dies auf a beschränkt ist bestimmte glibc version oder was auch immer.