Mehrere glibc-Bibliotheken auf einem einzigen Host
Mein Linux-Server (SLES-8) hat derzeit glibc-2.2.5-235, aber ich habe ein Programm, das mit dieser Version nicht funktioniert und glibc-2.3.3 benötigt.
Ist es möglich, mehrere Glibcs auf demselben Host zu installieren?
Dies ist der Fehler, den ich bekomme, wenn ich mein Programm auf dem alten glibc ausführe:
./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./myapp)
./myapp: /lib/i686/libpthread.so.0: version `GLIBC_2.3.2' not found (required by ./myapp)
./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libxerces-c.so.27)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./libstdc++.so.6)
./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libstdc++.so.6)
Also habe ich ein neues Verzeichnis namens newglibc erstellt und die folgenden Dateien kopiert:
libpthread.so.0
libm.so.6
libc.so.6
ld-2.3.3.so
ld-linux.so.2 -> ld-2.3.3.so
und
export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH
Aber ich bekomme eine Fehlermeldung:
./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libpthread.so.0)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by libstdc++.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libm.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./newglibc/libc.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libc.so.6)
Es scheint also, dass sie immer noch mit / lib verknüpft sind und nicht dort weitermachen, wo ich sie abgelegt habe?
Vielen Dank
export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH
hat das Problem für mich gelöst! Es wird sicherlich nicht für alle funktionieren, aber es ist eine einfache Lösung, wenn es funktioniert! Vielen Dank! :)Antworten:
Es ist sehr gut möglich, mehrere Versionen von glibc auf demselben System zu haben (das tun wir jeden Tag).
Sie müssen jedoch wissen, dass glibc aus vielen Teilen (mehr als 200 gemeinsam genutzte Bibliotheken) besteht, die alle übereinstimmen müssen. Eines der Teile ist ld-linux.so.2 und muss mit libc.so.6 übereinstimmen. Andernfalls werden die angezeigten Fehler angezeigt.
Der absolute Pfad zu ld-linux.so.2 ist zum Zeitpunkt der Verknüpfung fest in der ausführbaren Datei codiert und kann nach Abschluss der Verknüpfung nicht einfach geändert werden.
Gehen Sie folgendermaßen vor, um eine ausführbare Datei zu erstellen, die mit dem neuen glibc funktioniert:
Mit der
-rpath
Linker-Option sucht der Runtime Loader nach Bibliotheken in/path/to/newglibc
(damit Sie diese nicht festlegen müssen,LD_LIBRARY_PATH
bevor Sie sie ausführen), und die-dynamic-linker
Option "backt" den Pfad, um sield-linux.so.2
in der Anwendung zu korrigieren .Wenn Sie die
myapp
Anwendung nicht erneut verknüpfen können (z. B. weil es sich um eine Binärdatei eines Drittanbieters handelt), ist nicht alles verloren, aber es wird schwieriger. Eine Lösung besteht darin, eine geeignetechroot
Umgebung dafür festzulegen. Eine weitere Möglichkeit ist die Verwendung rtldi und einem Binär - Editor .quelle
-Wl,--dynamic-linker=file
(dauert zwei '-') nur beim Kompilieren für ausführbare ELF-Dateien funktioniert. Check/sbin/ldconfig -p | grep ld
patchelf
( nixos.org/patchelf.html ) verwenden, mit dem Sie den Pfad und den Interpreter des bereits kompilierten ELF ändern können.-Wl,--rpath
anstattLD_LIBRARY_PATH
aus anderen Gründen als Bequemlichkeit wichtig sein kann: Wenn das Programm startet Child - Prozesse, der WertLD_LIBRARY_PATH
wird in der Regel von ihnen geerbt werden, aber wenn sie nicht auch auf die Verwendung zusammengestellt Das neuere glibc (zum Beispiel, wenn es sich um Standard-Binärdateien handeltbash
) wird nicht gestartet./path/to/newglibc/ld-linux.so.2 --library-path /path/tonewglibc/lib64:/path/to/newglibc/usr/lib64 /path/to/myapp
-I
und-L
: stackoverflow.com/a/52454603/895245Diese Frage ist alt, die anderen Antworten sind alt. Die Antwort von "Employed Russian" ist sehr gut und informativ, funktioniert aber nur, wenn Sie den Quellcode haben. Wenn Sie dies nicht tun, waren die Alternativen damals sehr schwierig. Glücklicherweise haben wir heutzutage eine einfache Lösung für dieses Problem (wie in einer seiner Antworten kommentiert), indem wir patchelf verwenden . Alles was du tun musst, ist:
Und danach können Sie einfach Ihre Datei ausführen:
Zum
chroot
Glück müssen keine Binärdateien manuell bearbeitet werden. Denken Sie jedoch daran, Ihre Binärdatei vor dem Patchen zu sichern, wenn Sie nicht sicher sind, was Sie tun, da dadurch Ihre Binärdatei geändert wird. Nachdem Sie es gepatcht haben, können Sie den alten Pfad nicht zu Interpreter / Pfad wiederherstellen. Wenn es nicht funktioniert, müssen Sie es so lange patchen, bis Sie den Pfad gefunden haben, der tatsächlich funktioniert ... Nun, es muss kein Versuch-und-Irrtum-Prozess sein. In OPs Beispiel benötigte er beispielsweiseGLIBC_2.3
, damit Sie leicht herausfinden können, welche Bibliothek diese Version bereitstellt, indem Siestrings
:Theoretisch würde der erste grep leer sein, weil die Systembibliothek nicht die gewünschte Version hat, und der zweite sollte GLIBC_2.3 ausgeben, weil die Version verwendet
myapp
wird, damit wir wissen, dass wirpatchelf
unsere Binärdatei über diesen Pfad verwenden können.Wenn Sie versuchen, eine Binärdatei unter Linux auszuführen, versucht die Binärdatei, den Linker und dann die Bibliotheken zu laden, und alle sollten sich im Pfad und / oder an der richtigen Stelle befinden. Wenn Ihr Problem mit dem Linker besteht und Sie herausfinden möchten, nach welchem Pfad Ihre Binärdatei sucht, können Sie dies mit dem folgenden Befehl herausfinden:
Wenn Sie Probleme mit den Bibliotheken haben, können Sie folgende Befehle eingeben:
Dadurch werden die Bibliotheken aufgelistet, die Ihre Binärdatei benötigt, aber Sie kennen wahrscheinlich bereits die problematischen, da sie wie im Fall von OP bereits Fehler liefern.
"patchelf" funktioniert bei vielen verschiedenen Problemen, die beim Ausführen eines Programms auftreten können, die mit diesen beiden Problemen zusammenhängen. Wenn Sie beispielsweise: erhalten
ELF file OS ABI invalid
, kann dies behoben werden, indem Sie einen neuen Loader (den--set-interpreter
Teil des Befehls) festlegen, wie ich hier erläutere . Ein weiteres Beispiel ist das ProblemNo such file or directory
beim Abrufen einer Datei, die vorhanden und ausführbar ist, wie hier dargestellt . In diesem speziellen Fall fehlte OP ein Link zum Loader, aber in Ihrem Fall haben Sie möglicherweise keinen Root-Zugriff und können den Link nicht erstellen. Das Einstellen eines neuen Dolmetschers würde Ihr Problem lösen.Vielen Dank an Employed Russian und Michael Pankov für den Einblick und die Lösung!
quelle
patchelf
), aber der Satz "Keine Notwendigkeit ... Binärdateien zu bearbeiten" kann etwas irreführend sein (da Sie Ihre Binärdateien tatsächlich bearbeiten).Verwenden Sie LD_PRELOAD: Legen Sie Ihre Bibliothek irgendwo außerhalb der man lib-Verzeichnisse ab und führen Sie Folgendes aus:
Siehe: den Wikipedia-Artikel
quelle
Zuallererst ist die wichtigste Abhängigkeit jedes dynamisch verknüpften Programms der Linker. Alle Bibliotheken müssen also mit der Version des Linkers übereinstimmen.
Nehmen wir ein einfaches Beispiel: Ich habe das Newset-Ubuntu-System, auf dem ich ein Programm ausführe (in meinem Fall ist es D-Compiler - ldc2). Ich würde es gerne auf dem alten CentOS ausführen, aber aufgrund der älteren glibc-Bibliothek ist es unmöglich. ich habe
Ich muss alle Abhängigkeiten von Ubuntu nach Centos kopieren. Die richtige Methode ist folgende:
Lassen Sie uns zunächst alle Abhängigkeiten überprüfen:
linux-vdso.so.1 ist keine echte Bibliothek und wir müssen uns nicht darum kümmern.
/lib64/ld-linux-x86-64.so.2 ist der Linker, der vom Linux verwendet wird, um die ausführbare Datei mit allen dynamischen Bibliotheken zu verknüpfen.
Die restlichen Dateien sind echte Bibliotheken und alle müssen zusammen mit dem Linker irgendwo in den Centos kopiert werden.
Nehmen wir an, alle Bibliotheken und Linker befinden sich im Verzeichnis "/ mylibs".
ld-linux-x86-64.so.2 ist - wie ich bereits sagte - der Linker. Es ist keine dynamische Bibliothek, sondern eine statische ausführbare Datei. Sie können es ausführen und sehen, dass es sogar einige Parameter hat, z. B. --library-path (ich werde darauf zurückkommen).
Unter Linux kann ein dynamisch verknüpftes Programm nur anhand seines Namens zu Mittag gegessen werden, z
Linux lädt ein solches Programm in den Arbeitsspeicher und prüft, welcher Linker dafür eingestellt ist. Normalerweise ist es auf einem 64-Bit-System /lib64/ld-linux-x86-64.so.2 (in Ihrem Dateisystem ist es eine symbolische Verknüpfung zur realen ausführbaren Datei). Dann führt Linux den Linker aus und lädt dynamische Bibliotheken.
Sie können dies auch ein wenig ändern und einen solchen Trick ausführen:
Dies ist die Methode, um das Linux zu zwingen, einen bestimmten Linker zu verwenden.
Und jetzt können wir zu dem zuvor erwähnten Parameter --library-path zurückkehren
Es wird ldc2 ausführen und dynamische Bibliotheken aus / mylibs laden.
Dies ist die Methode zum Aufrufen der ausführbaren Datei mit ausgewählten (nicht systemstandardisierten) Bibliotheken.
quelle
Setup 1: Kompilieren Sie Ihren eigenen glibc ohne dedizierten GCC und verwenden Sie ihn
Dieses Setup funktioniert möglicherweise und ist schnell, da nicht die gesamte GCC-Toolchain neu kompiliert wird, sondern nur glibc.
Aber es ist nicht zuverlässig , wie es Host - C - Laufzeit - Objekte verwendet wie
crt1.o
,crti.o
undcrtn.o
von glibc zur Verfügung gestellt. Dies wird erwähnt unter: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Diese Objekte führen eine frühe Einrichtung durch, auf die sich glibc stützt. Ich wäre also nicht überrascht, wenn die Dinge wunderbar abstürzen würden und unglaublich subtile Wege.Eine zuverlässigere Einrichtung finden Sie unter Setup 2 unten.
Erstellen Sie glibc und installieren Sie es lokal:
Setup 1: Überprüfen Sie den Build
test_glibc.c
Kompilieren und ausführen mit
test_glibc.sh
:Das Programm gibt Folgendes aus:
Befehl angepasst von https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location, aber
--sysroot
fehlgeschlagen mit:also habe ich es entfernt.
ldd
Die Ausgabe bestätigt, dass dieldd
und Bibliotheken, die wir gerade erstellt haben, tatsächlich wie erwartet verwendet werden:Die
gcc
Debug-Ausgabe der Kompilierung zeigt, dass meine Host-Laufzeitobjekte verwendet wurden, was, wie bereits erwähnt, schlecht ist, aber ich weiß nicht, wie ich es umgehen soll, z. B. enthält es:Setup 1: Glibc ändern
Jetzt ändern wir glibc mit:
Dann kompilieren Sie glibc neu und installieren Sie es erneut. Kompilieren Sie unser Programm neu und führen Sie es erneut aus:
und wir sehen
hacked
einige Male wie erwartet gedruckt.Dies bestätigt weiter, dass wir tatsächlich den von uns kompilierten Glibc verwendet haben und nicht den Host.
Getestet unter Ubuntu 18.04.
Setup 2: Crosstool-NG makelloses Setup
Dies ist eine Alternative zur Einrichtung 1, und es ist die richtige Setup ich bisher erreicht habe: alles korrekt ist, soweit ich beobachten kann, einschließlich der C - Laufzeit - Objekte wie
crt1.o
,crti.o
, undcrtn.o
.In diesem Setup kompilieren wir eine vollständige dedizierte GCC-Toolchain, die den gewünschten glibc verwendet.
Der einzige Nachteil dieser Methode ist, dass der Build länger dauert. Aber ich würde kein Produktionssetup mit weniger riskieren.
crosstool-NG ist eine Reihe von Skripten, die alles von der Quelle für uns herunterladen und kompilieren, einschließlich GCC, glibc und binutils.
Ja, das GCC-Build-System ist so schlecht, dass wir dafür ein separates Projekt benötigen.
Dieses Setup ist nur nicht perfekt, da Crosstool-NG das Erstellen der ausführbaren Dateien ohne zusätzliche
-Wl
Flags nicht unterstützt , was sich seltsam anfühlt, da wir GCC selbst erstellt haben. Aber alles scheint zu funktionieren, daher ist dies nur eine Unannehmlichkeit.Holen Sie sich Crosstool-NG, konfigurieren und erstellen Sie es:
Der Bau dauert etwa dreißig Minuten bis zwei Stunden.
Die einzige obligatorische Konfigurationsoption, die ich sehen kann, besteht darin, sie an Ihre Host-Kernel-Version anzupassen, um die richtigen Kernel-Header zu verwenden. Finden Sie Ihre Host-Kernel-Version mit:
was mir zeigt:
also
menuconfig
mache ich:Operating System
Version of linux
also wähle ich:
Dies ist die erste gleiche oder ältere Version. Es muss älter sein, da der Kernel abwärtskompatibel ist.
Setup 2: optionale Konfigurationen
Das
.config
, mit dem wir generiert haben,./ct-ng x86_64-unknown-linux-gnu
hat:Um dies zu ändern,
menuconfig
tun Sie Folgendes:C-library
Version of glibc
Speichern Sie die
.config
und fahren Sie mit dem Build fort.Oder, wenn Sie Ihre eigene glibc Quelle verwenden möchten, zB glibc aus dem aktuellen git zu verwenden, gehen Sie wie folgt aus :
Paths and misc options
Try features marked as EXPERIMENTAL
: auf true setzenC-library
Source of glibc
Custom location
: Sag jaCustom location
Custom source location
: Zeigen Sie auf ein Verzeichnis, das Ihre Glibc-Quelle enthältwo glibc geklont wurde als:
Setup 2: Testen Sie es
Sobald Sie die gewünschte Toolchain erstellt haben, testen Sie sie mit:
Alles scheint wie in Setup 1 zu funktionieren, außer dass jetzt die richtigen Laufzeitobjekte verwendet wurden:
Setup 2: Fehlgeschlagener effizienter Glibc-Neukompilierungsversuch
Mit Crosstool-NG scheint dies nicht möglich zu sein, wie unten erläutert.
Wenn Sie nur neu erstellen;
Dann werden Ihre Änderungen am benutzerdefinierten Glibc-Quellspeicherort berücksichtigt, aber alles wird von Grund auf neu erstellt, sodass es für die iterative Entwicklung unbrauchbar wird.
Wenn wir es tun:
Es gibt einen schönen Überblick über die Build-Schritte:
Daher sehen wir, dass es glibc-Schritte gibt, die mit mehreren GCC-Schritten verflochten sind, insbesondere
libc_start_files
vorhercc_core_pass_2
, was wahrscheinlich der teuerste Schritt zusammen mit istcc_core_pass_1
.Um nur einen Schritt zu erstellen, müssen Sie zuerst die
.config
Option "Zwischenschritte speichern" in der Option für den ersten Build festlegen:Paths and misc options
Debug crosstool-NG
Save intermediate steps
und dann können Sie versuchen:
aber leider ist das
+
erforderlich wie erwähnt unter: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536 angegebenund im Grunde macht der Wiederaufbau immer noch zu langsam, um für die Entwicklung machbar zu sein, und ich sehe nicht, wie ich dies überwinden kann, ohne Crosstool-NG zu patchen.
Darüber hinaus
libc
schien das Ausführen des Schritts nicht erneut von der Quelle zu kopierenCustom source location
, was diese Methode weiter unbrauchbar machte.Bonus: stdlibc ++
Ein Bonus, wenn Sie auch an der C ++ - Standardbibliothek interessiert sind: Wie kann ich die GCC libstdc ++ C ++ - Standardbibliotheksquelle bearbeiten und neu erstellen?
quelle
Können Sie Nix http://nixos.org/nix/ verwenden ?
quelle
@msb gibt eine sichere Lösung.
Ich bin auf dieses Problem
import tensorflow as tf
gestoßen, als ich es in einer Conda-Umgebung gemacht habeCentOS 6.5
der es nur gibtglibc-2.12
.Ich möchte einige Details liefern:
Zuerst installieren
glibc
in Ihrem Home-Verzeichnis:Zweitens folgen Sie der Installation auf die gleiche Weise Patchelf .
Drittens patchen Sie Ihren Python:
wie von @msb erwähnt
Jetzt kann ich verwenden
tensorflow-2.0 alpha
in verwendenCentOS 6.5
.ref: https://serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/
quelle
Ich bin nicht sicher, ob die Frage noch relevant ist, aber es gibt eine andere Möglichkeit, das Problem zu beheben: Docker. Man kann einen fast leeren Container der Quelldistribution (die für die Entwicklung verwendete Distribution) installieren und die Dateien in den Container kopieren. Auf diese Weise müssen Sie nicht das für chroot erforderliche Dateisystem erstellen.
quelle
Wenn Sie sich die zweite Ausgabe genau ansehen, können Sie sehen, dass der neue Speicherort für die Bibliotheken verwendet wird. Vielleicht fehlen noch Bibliotheken, die Teil des glibc sind.
Ich denke auch, dass alle von Ihrem Programm verwendeten Bibliotheken gegen diese Version von glibc kompiliert werden sollten. Wenn Sie Zugriff auf den Quellcode des Programms haben, scheint eine neue Kompilierung die beste Lösung zu sein.
quelle
"Employed Russian" gehört zu den besten Antworten, und ich denke, alle anderen vorgeschlagenen Antworten funktionieren möglicherweise nicht. Der Grund liegt einfach darin, dass beim erstmaligen Erstellen einer Anwendung alle benötigten APIs zur Kompilierungszeit aufgelöst werden. Mit "ldd" können Sie alle statisch verknüpften Abhängigkeiten anzeigen:
Zur Laufzeit lädt Firefox aber auch viele andere dynamische Bibliotheken, z. B. (für Firefox) sind viele Bibliotheken mit "glib" -Labels geladen (obwohl statisch verknüpft keine vorhanden sind):
Oft sehen Sie, wie Namen einer Version mit einer anderen Version verknüpft werden. Z.B:
Dies bedeutet daher, dass in einem System unterschiedliche Versionen von "Bibliotheken" vorhanden sind. Dies ist kein Problem, da es sich um dieselbe Datei handelt, und bietet Kompatibilität, wenn Anwendungen von mehreren Versionen abhängig sind.
Auf Systemebene sind daher fast alle Bibliotheken voneinander abhängig, und es ändert nichts, nur die Ladepriorität der Bibliotheken durch Manipulieren von LD_PRELOAD oder LD_LIBRARY_PATH zu ändern - selbst wenn sie geladen werden können, kann es zur Laufzeit immer noch zum Absturz kommen.
http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc
Die beste Alternative ist chroot (von ER kurz erwähnt): Dazu müssen Sie jedoch die gesamte Umgebung neu erstellen, in der sich die ursprüngliche binäre Ausführung befindet - normalerweise beginnend mit / lib, / usr / lib /, / usr / lib / x86 usw. Sie können entweder "Buildroot" oder YoctoProject verwenden oder einfach nur aus einer vorhandenen Distro-Umgebung tarieren. (wie Fedora / Suse usw.).
quelle
Als ich einen Chrom-Browser unter Ubuntu präzise ausführen wollte (glibc-2.15), bekam ich die (typische) Meldung "... libc.so.6: Version` GLIBC_2.19 'nicht gefunden ... ". Ich habe die Tatsache berücksichtigt, dass Dateien nicht dauerhaft benötigt werden, sondern nur zum Starten. Also habe ich die für den Browser und sudo benötigten Dateien gesammelt und eine Mini-Glibc-2.19-Umgebung erstellt, den Browser gestartet und dann die Originaldateien wieder kopiert. Die benötigten Dateien befinden sich im RAM und der ursprüngliche glibc ist der gleiche.
mkdir -p /glibc-2.19/i386-linux-gnu
mkdir -p /glibc-2.15/i386-linux-gnu
das Skript zum Ausführen des Browsers:
quelle