Mehrere glibc-Bibliotheken auf einem einzigen Host


171

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


1
Gleiches Problem mit dem SLES-11-Server. Kann nicht aktualisieren und brauche aktuelle Sachen. oh mein ...
UmNyobe

FWIW, 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! :)
Rinogo

Antworten:


229

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:

g++ main.o -o myapp ... \
   -Wl,--rpath=/path/to/newglibc \
   -Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2

Mit der -rpathLinker-Option sucht der Runtime Loader nach Bibliotheken in /path/to/newglibc(damit Sie diese nicht festlegen müssen, LD_LIBRARY_PATHbevor Sie sie ausführen), und die -dynamic-linkerOption "backt" den Pfad, um sie ld-linux.so.2in der Anwendung zu korrigieren .

Wenn Sie die myappAnwendung 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 geeignete chrootUmgebung dafür festzulegen. Eine weitere Möglichkeit ist die Verwendung rtldi und einem Binär - Editor .


3
Beachten Sie, dass -Wl,--dynamic-linker=file(dauert zwei '-') nur beim Kompilieren für ausführbare ELF-Dateien funktioniert. Check/sbin/ldconfig -p | grep ld
Tom

49
Jetzt können Sie ein praktisches Dienstprogramm patchelf( nixos.org/patchelf.html ) verwenden, mit dem Sie den Pfad und den Interpreter des bereits kompilierten ELF ändern können.
Michael Pankov

10
Es ist erwähnenswert , dass der Pfad zum neuen glibc Angabe verwendet , -Wl,--rpathanstatt LD_LIBRARY_PATHaus anderen Gründen als Bequemlichkeit wichtig sein kann: Wenn das Programm startet Child - Prozesse, der Wert LD_LIBRARY_PATHwird 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 handelt bash) wird nicht gestartet.
HighCommander4

13
Eine andere Möglichkeit besteht darin, die neue ld.so direkt auszuführen und ihr Binärprogramm als Parameter zu übergeben. Dies ersetzt effektiv ld.so verwendet, ohne dass das Programm neu kompiliert werden muss:/path/to/newglibc/ld-linux.so.2 --library-path /path/tonewglibc/lib64:/path/to/newglibc/usr/lib64 /path/to/myapp
maximk


67

Diese 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:

$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp

Und danach können Sie einfach Ihre Datei ausführen:

$ ./myapp

Zum chrootGlü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 beispielsweise GLIBC_2.3, damit Sie leicht herausfinden können, welche Bibliothek diese Version bereitstellt, indem Sie strings:

$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3

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 myappwird, damit wir wissen, dass wir patchelfunsere 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:

$ readelf -l myapp | grep interpreter
  [Requesting program interpreter: /lib/ld-linux.so.2]                                                                                                                                                                                   

Wenn Sie Probleme mit den Bibliotheken haben, können Sie folgende Befehle eingeben:

$ readelf -d myapp | grep Shared
$ ldd myapp 

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-interpreterTeil des Befehls) festlegen, wie ich hier erläutere . Ein weiteres Beispiel ist das Problem No such file or directorybeim 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!


1
Das war am hilfreichsten! Ich habe Python Binary gepatcht, um neues Glibc für Tensorflow zu verwenden
Faizan

Dies ist eine nette Lösung (von der ich vorher nichts gewusst hatte patchelf), aber der Satz "Keine Notwendigkeit ... Binärdateien zu bearbeiten" kann etwas irreführend sein (da Sie Ihre Binärdateien tatsächlich bearbeiten).
Larsks

Dort behoben. ;)
msb

Wirklich hilfreiches Dienstprogramm! Danke dir! Obwohl ich erst nach stundenlangem manuellen Auflösen von Abhängigkeiten einen Segmentierungsfehler erhalten und dann alles gepatcht habe, um Chrome ohne Administratorrechte lokal zu installieren ...
G. Bergeron

@fgiraldeau danke für das Kompliment. :) aber die Frage wurde 2009 gestellt, beantwortet und akzeptiert. Ich würde nicht erwarten, dass jemand 8 Jahre wartet, bevor er eine Antwort akzeptiert. heheh; D
msb

20

Verwenden Sie LD_PRELOAD: Legen Sie Ihre Bibliothek irgendwo außerhalb der man lib-Verzeichnisse ab und führen Sie Folgendes aus:

LD_PRELOAD='mylibc.so anotherlib.so' program

Siehe: den Wikipedia-Artikel


1
dachte, dies wäre eine gute Lösung für ein komplexes Makefile, aber es funktionierte nicht für mich
Galactica

Das ist nützlich, besonders die, die keine Quelle binär sind. Danke
Codierer

2
ähm ... ich habe mich geirrt, es scheint, als müsste ich die ld-linux.so nach / path / to / new / lib / frist rpathieren, während die Quelle kompiliert und verlinkt wird
Codierer

1
Dies funktioniert nicht, wenn ld - #. ##. Also (von Ihrem System glibc lib) nicht die gleiche glibc-Version wie libc.so ist. # (Von Ihrer alternativen glibc lib)
Andy

12

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

ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)

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:

ldd ldc2-1.5.0-linux-x86_64/bin/ldc2 
    linux-vdso.so.1 =>  (0x00007ffebad3f000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)

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

/bin/ldc2

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:

/mylibs/ld-linux-x86-64.so.2 /bin/ldc2

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

/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2

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.


Ich habe ein Programm auf RH7 kompiliert und brauche es, um auf RH6 zu laufen. Ich wollte keine neue ausführbare Datei erstellen oder Patchelf verwenden, daher ist dies eine großartige Alternative.
Mark Rajcok

9

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.ound crtn.ovon 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:

export glibc_install="$(pwd)/glibc/build/install"

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
mkdir build
cd build
../configure --prefix "$glibc_install"
make -j `nproc`
make install -j `nproc`

Setup 1: Überprüfen Sie den Build

test_glibc.c

#define _GNU_SOURCE
#include <assert.h>
#include <gnu/libc-version.h>
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>

atomic_int acnt;
int cnt;

int f(void* thr_data) {
    for(int n = 0; n < 1000; ++n) {
        ++cnt;
        ++acnt;
    }
    return 0;
}

int main(int argc, char **argv) {
    /* Basic library version check. */
    printf("gnu_get_libc_version() = %s\n", gnu_get_libc_version());

    /* Exercise thrd_create from -pthread,
     * which is not present in glibc 2.27 in Ubuntu 18.04.
     * /programming/56810/how-do-i-start-threads-in-plain-c/52453291#52453291 */
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

Kompilieren und ausführen mit test_glibc.sh:

#!/usr/bin/env bash
set -eux
gcc \
  -L "${glibc_install}/lib" \
  -I "${glibc_install}/include" \
  -Wl,--rpath="${glibc_install}/lib" \
  -Wl,--dynamic-linker="${glibc_install}/lib/ld-linux-x86-64.so.2" \
  -std=c11 \
  -o test_glibc.out \
  -v \
  test_glibc.c \
  -pthread \
;
ldd ./test_glibc.out
./test_glibc.out

Das Programm gibt Folgendes aus:

gnu_get_libc_version() = 2.28
The atomic counter is 10000
The non-atomic counter is 8674

Befehl angepasst von https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location, aber --sysrootfehlgeschlagen mit:

cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install

also habe ich es entfernt.

lddDie Ausgabe bestätigt, dass die lddund Bibliotheken, die wir gerade erstellt haben, tatsächlich wie erwartet verwendet werden:

+ ldd test_glibc.out
        linux-vdso.so.1 (0x00007ffe4bfd3000)
        libpthread.so.0 => /home/ciro/glibc/build/install/lib/libpthread.so.0 (0x00007fc12ed92000)
        libc.so.6 => /home/ciro/glibc/build/install/lib/libc.so.6 (0x00007fc12e9dc000)
        /home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)

Die gccDebug-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:

COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o

Setup 1: Glibc ändern

Jetzt ändern wir glibc mit:

diff --git a/nptl/thrd_create.c b/nptl/thrd_create.c
index 113ba0d93e..b00f088abb 100644
--- a/nptl/thrd_create.c
+++ b/nptl/thrd_create.c
@@ -16,11 +16,14 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */

+#include <stdio.h>
+
 #include "thrd_priv.h"

 int
 thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
 {
+  puts("hacked");
   _Static_assert (sizeof (thr) == sizeof (pthread_t),
                   "sizeof (thr) != sizeof (pthread_t)");

Dann kompilieren Sie glibc neu und installieren Sie es erneut. Kompilieren Sie unser Programm neu und führen Sie es erneut aus:

cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh

und wir sehen hackedeinige 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, und crtn.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 -WlFlags 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:

git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout a6580b8e8b55345a5a342b5bd96e42c83e640ac5
export CT_PREFIX="$(pwd)/.build/install"
export PATH="/usr/lib/ccache:${PATH}"
./bootstrap
./configure --enable-local
make -j `nproc`
./ct-ng x86_64-unknown-linux-gnu
./ct-ng menuconfig
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

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:

uname -a

was mir zeigt:

4.15.0-34-generic

also menuconfigmache ich:

  • Operating System
    • Version of linux

also wähle ich:

4.14.71

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-gnuhat:

CT_GLIBC_V_2_27=y

Um dies zu ändern, menuconfigtun Sie Folgendes:

  • C-library
  • Version of glibc

Speichern Sie die .configund 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 setzen
  • C-library
    • Source of glibc
      • Custom location: Sag ja
      • Custom location
        • Custom source location: Zeigen Sie auf ein Verzeichnis, das Ihre Glibc-Quelle enthält

wo glibc geklont wurde als:

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28

Setup 2: Testen Sie es

Sobald Sie die gewünschte Toolchain erstellt haben, testen Sie sie mit:

#!/usr/bin/env bash
set -eux
install_dir="${CT_PREFIX}/x86_64-unknown-linux-gnu"
PATH="${PATH}:${install_dir}/bin" \
  x86_64-unknown-linux-gnu-gcc \
  -Wl,--dynamic-linker="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib/ld-linux-x86-64.so.2" \
  -Wl,--rpath="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib" \
  -v \
  -o test_glibc.out \
  test_glibc.c \
  -pthread \
;
ldd test_glibc.out
./test_glibc.out

Alles scheint wie in Setup 1 zu funktionieren, außer dass jetzt die richtigen Laufzeitobjekte verwendet wurden:

COLLECT_GCC_OPTIONS=/home/ciro/crosstool-ng/.build/install/x86_64-unknown-linux-gnu/bin/../x86_64-unknown-linux-gnu/sysroot/usr/lib/../lib64/crt1.o

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;

env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

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:

./ct-ng list-steps

Es gibt einen schönen Überblick über die Build-Schritte:

Available build steps, in order:
  - companion_tools_for_build
  - companion_libs_for_build
  - binutils_for_build
  - companion_tools_for_host
  - companion_libs_for_host
  - binutils_for_host
  - cc_core_pass_1
  - kernel_headers
  - libc_start_files
  - cc_core_pass_2
  - libc
  - cc_for_build
  - cc_for_host
  - libc_post_cc
  - companion_libs_for_target
  - binutils_for_target
  - debug
  - test_suite
  - finish
Use "<step>" as action to execute only that step.
Use "+<step>" as action to execute up to that step.
Use "<step>+" as action to execute from that step onward.

Daher sehen wir, dass es glibc-Schritte gibt, die mit mehreren GCC-Schritten verflochten sind, insbesondere libc_start_files vorher cc_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 .configOption "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:

env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`

aber leider ist das +erforderlich wie erwähnt unter: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536 angegeben

Beachten Sie jedoch, dass durch einen Neustart in einem Zwischenschritt das Installationsverzeichnis auf den Status zurückgesetzt wird, den es während dieses Schritts hatte. Das heißt, Sie werden eine neu erstellte libc haben - aber keinen endgültigen Compiler, der mit dieser libc erstellt wurde (und daher auch keine Compiler-Bibliotheken wie libstdc ++).

und 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 libcschien das Ausführen des Schritts nicht erneut von der Quelle zu kopieren Custom 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?


6

Können Sie Nix http://nixos.org/nix/ verwenden ?

Nix unterstützt die Paketverwaltung für mehrere Benutzer: Mehrere Benutzer können einen gemeinsamen Nix-Speicher sicher gemeinsam nutzen, benötigen keine Root-Rechte, um Software zu installieren, und können verschiedene Versionen eines Pakets installieren und verwenden.


4

@msb gibt eine sichere Lösung.

Ich bin auf dieses Problem import tensorflow as tfgestoßen, als ich es in einer Conda-Umgebung gemacht habeCentOS 6.5 der es nur gibt glibc-2.12.

ImportError: /lib64/libc.so.6: version `GLIBC_2.16' not found (required by /home/

Ich möchte einige Details liefern:

Zuerst installieren glibc in Ihrem Home-Verzeichnis:

mkdir ~/glibc-install; cd ~/glibc-install
wget http://ftp.gnu.org/gnu/glibc/glibc-2.17.tar.gz
tar -zxvf glibc-2.17.tar.gz
cd glibc-2.17
mkdir build
cd build
../configure --prefix=/home/myself/opt/glibc-2.17  # <-- where you install new glibc
make -j<number of CPU Cores>  # You can find your <number of CPU Cores> by using **nproc** command
make install

Zweitens folgen Sie der Installation auf die gleiche Weise Patchelf .

Drittens patchen Sie Ihren Python:

[myself@nfkd ~]$ patchelf --set-interpreter /home/myself/opt/glibc-2.17/lib/ld-linux-x86-64.so.2 --set-rpath /home/myself/opt/glibc-2.17/lib/ /home/myself/miniconda3/envs/tensorflow/bin/python

wie von @msb erwähnt

Jetzt kann ich verwenden tensorflow-2.0 alpha in verwenden CentOS 6.5.

ref: https://serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/


2

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.


1

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.


1

"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:

ldd /usr/lib/firefox/firefox
    linux-vdso.so.1 =>  (0x00007ffd5c5f0000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f727e708000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f727e500000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f727e1f8000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f727def0000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f727db28000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f727eb78000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f727d910000)

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):

 /usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2.2.2
 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0
 /usr/lib/x86_64-linux-gnu/libavahi-glib.so.1.0.2

Oft sehen Sie, wie Namen einer Version mit einer anderen Version verknüpft werden. Z.B:

lrwxrwxrwx 1 root root     23 Dec 21  2014 libdbus-glib-1.so.2 -> libdbus-glib-1.so.2.2.2
-rw-r--r-- 1 root root 160832 Mar  1  2013 libdbus-glib-1.so.2.2.2

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.).


0

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.

as root
the files (*-2.15.so) already exist 

mkdir -p /glibc-2.19/i386-linux-gnu

/glibc-2.19/ld-linux.so.2 -> /glibc-2.19/i386-linux-gnu/ld-2.19.so
/glibc-2.19/i386-linux-gnu/libc.so.6 -> libc-2.19.so
/glibc-2.19/i386-linux-gnu/libdl.so.2 -> libdl-2.19.so
/glibc-2.19/i386-linux-gnu/libpthread.so.0 -> libpthread-2.19.so

mkdir -p /glibc-2.15/i386-linux-gnu

/glibc-2.15/ld-linux.so.2 -> (/glibc-2.15/i386-linux-gnu/ld-2.15.so)
/glibc-2.15/i386-linux-gnu/libc.so.6 -> (libc-2.15.so)
/glibc-2.15/i386-linux-gnu/libdl.so.2 -> (libdl-2.15.so)
/glibc-2.15/i386-linux-gnu/libpthread.so.0 -> (libpthread-2.15.so)

das Skript zum Ausführen des Browsers:

#!/bin/sh
sudo cp -r /glibc-2.19/* /lib
/path/to/the/browser &
sleep 1
sudo cp -r /glibc-2.15/* /lib
sudo rm -r /lib/i386-linux-gnu/*-2.19.so
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.