Wiele bibliotek glibc na jednym hoście

171

Wiele bibliotek glibc na jednym hoście

Mój serwer linux (SLES-8) ma obecnie glibc-2.2.5-235, ale mam program, który nie będzie działał w tej wersji i wymaga glibc-2.3.3.

Czy można zainstalować wiele bibliotek glibcs ​​na tym samym hoście?

Oto błąd, który pojawia się, gdy uruchamiam program na starym glibc:

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

Utworzyłem więc nowy katalog o nazwie newglibc i skopiowałem następujące pliki w:

libpthread.so.0
libm.so.6
libc.so.6
ld-2.3.3.so
ld-linux.so.2 -> ld-2.3.3.so

i

export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH

Ale pojawia się błąd:

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

Wygląda więc na to, że nadal łączą się z / lib i nie pobierają z miejsca, w którym je umieściłem?

Dzięki

dogbane
źródło
1
ten sam problem z serwerem SLES-11. Nie można zaktualizować i potrzebuję najnowszych rzeczy. o mój ...
UmNyobe,
FWIW, export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH nie rozwiązuje problemu dla mnie! To z pewnością nie zadziała dla wszystkich, ale jeśli zadziała, można to łatwo naprawić! Dzięki! :)
rinogo

Odpowiedzi:

229

Bardzo możliwe jest posiadanie wielu wersji glibc w tym samym systemie (robimy to codziennie).

Musisz jednak wiedzieć, że glibc składa się z wielu elementów (ponad 200 współdzielonych bibliotek), które muszą pasować. Jeden z elementów to ld-linux.so.2 i musi pasować do libc.so.6, w przeciwnym razie zobaczysz błędy, które widzisz.

Bezwzględna ścieżka do ld-linux.so.2 jest zakodowana na stałe w pliku wykonywalnym w czasie łączenia i nie można jej łatwo zmienić po utworzeniu łącza.

Aby zbudować plik wykonywalny, który będzie działał z nowym glibc, wykonaj następujące czynności:

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

Opcja -rpathkonsolidatora sprawi, że program ładujący środowiska uruchomieniowego wyszuka biblioteki w programie /path/to/newglibc(więc nie trzeba go ustawiać LD_LIBRARY_PATHprzed uruchomieniem), a -dynamic-linkeropcja „upiecze” ścieżkę do poprawienia ld-linux.so.2w aplikacji.

Jeśli nie możesz ponownie połączyć myappaplikacji (np. Ponieważ jest to plik binarny innej firmy), nie wszystko jest stracone, ale staje się to trudniejsze. Jednym z rozwiązań jest ustawienie chrootdla niego odpowiedniego środowiska. Inną możliwością jest użycie rtldi i edytora binarnego .

Zatrudniony Rosjanin
źródło
3
Zauważ, że -Wl,--dynamic-linker=file(bierze dwa '-') działa tylko podczas kompilacji dla plików wykonywalnych ELF. Sprawdź/sbin/ldconfig -p | grep ld
Tomek
49
Teraz możesz użyć wygodnego narzędzia patchelf( nixos.org/patchelf.html ), które pozwala na modyfikację rpath i interpretera już skompilowanego ELF.
Michael Pankov,
10
Warto wspomnieć, że określenie ścieżki do nowego glibc przy użyciu, -Wl,--rpatha nie LD_LIBRARY_PATHmoże być ważne z powodów innych niż wygoda: jeśli program uruchamia procesy potomne, wartość LD_LIBRARY_PATHbędzie zwykle przez nie dziedziczona, ale jeśli nie są one również skompilowane do użycia nowszy glibc (na przykład, jeśli są standardowymi plikami binarnymi bash), nie zostaną uruchomione.
HighCommander4
13
Inną opcją jest bezpośrednie uruchomienie nowego ld.so, przekazując mu swój program binarny jako parametr; to skutecznie zastąpi ld.so używany bez konieczności rekompilacji programu:/path/to/newglibc/ld-linux.so.2 --library-path /path/tonewglibc/lib64:/path/to/newglibc/usr/lib64 /path/to/myapp
maksymk
Potrzebowałem również -Ii -L: stackoverflow.com/a/52454603/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
67

To pytanie jest stare, inne odpowiedzi są stare. Odpowiedź „Zatrudniony Rosjanin” jest bardzo dobra i zawiera wiele informacji, ale działa tylko wtedy, gdy masz kod źródłowy. Jeśli tego nie zrobisz, wówczas alternatywy były bardzo trudne. Na szczęście w dzisiejszych czasach mamy proste rozwiązanie tego problemu (jak skomentował w jednej z jego odpowiedzi), używając patchelf . Wszystko co musisz zrobić to:

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

A potem możesz po prostu uruchomić swój plik:

$ ./myapp

Na chrootszczęście nie ma potrzeby ręcznego edytowania plików binarnych. Pamiętaj jednak, aby wykonać kopię zapasową swojego pliku binarnego przed jego łataniem, jeśli nie jesteś pewien, co robisz, ponieważ modyfikuje on plik binarny. Po jej poprawieniu nie można przywrócić starej ścieżki do interpreter / rpath. Jeśli to nie zadziała, będziesz musiał go poprawiać, aż znajdziesz ścieżkę, która faktycznie zadziała ... Cóż, nie musi to być proces prób i błędów. Na przykład w przykładzie OP potrzebował GLIBC_2.3, więc możesz łatwo znaleźć, która biblioteka udostępnia tę wersję, używając strings:

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

Teoretycznie pierwszy plik grep byłby pusty, ponieważ libc systemowy nie ma żądanej wersji, a drugi powinien wypisać GLIBC_2.3, ponieważ ma wersję, z której myappkorzysta, więc wiemy, że możemy patchelfużyć tej ścieżki do naszego pliku binarnego.

Kiedy próbujesz uruchomić plik binarny w Linuksie, plik binarny próbuje załadować konsolidator, a następnie biblioteki i wszystkie powinny znajdować się na ścieżce i / lub we właściwym miejscu. Jeśli masz problem z linkerem i chcesz dowiedzieć się, jakiej ścieżki szuka Twój plik binarny, możesz dowiedzieć się za pomocą tego polecenia:

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

Jeśli problem dotyczy bibliotek, polecenia, które podadzą używane biblioteki, to:

$ readelf -d myapp | grep Shared
$ ldd myapp 

Spowoduje to wyświetlenie bibliotek, których potrzebuje twój plik binarny, ale prawdopodobnie znasz już problematyczne, ponieważ już zawierają błędy, jak w przypadku OP.

„patchelf” działa w przypadku wielu różnych problemów, które mogą wystąpić podczas próby uruchomienia programu, związanych z tymi dwoma problemami. Na przykład, jeśli otrzymasz:, ELF file OS ABI invalidmożna to naprawić, ustawiając nowy program ładujący ( --set-interpreterczęść polecenia), jak wyjaśnię tutaj . Innym przykładem jest problem z pobieraniem No such file or directorypo uruchomieniu pliku, który istnieje i jest wykonywalny, jak pokazano tutaj . W tym konkretnym przypadku OP brakowało łącza do programu ładującego, ale być może w twoim przypadku nie masz uprawnień administratora i nie możesz utworzyć łącza. Ustawienie nowego tłumacza rozwiązałoby twój problem.

Dziękuję Zatrudniony Rosjanin i Michael Pankov za wgląd i rozwiązanie!

msb
źródło
1
To było najbardziej pomocne! I połatany Pythona binarne użyć nowego glibc dla tensorflow
Faizan
Jest to zgrabne rozwiązanie (o którym wcześniej nie wiedziałem patchelf), ale fraza „Nie ma potrzeby ... edycji plików binarnych” może być trochę myląca (ponieważ faktycznie edytujesz pliki binarne).
larsks
Tam, naprawione. ;)
msb
Naprawdę pomocne narzędzie! Dziękuję Ci! Chociaż udało mi się uzyskać błąd segmentacji dopiero po godzinach ręcznego rozwiązywania zależności, a następnie łatania wszystkiego, aby lokalnie zainstalować Chrome bez uprawnień administratora ...
G. Bergeron
@fgiraldeau dzięki za komplement. :) ale pytanie zostało zadane, udzielone i zaakceptowane w 2009 roku, nie spodziewałbym się, że ktoś będzie czekał 8 lat przed przyjęciem odpowiedzi. heheh; D
msb
20

Użyj LD_PRELOAD: umieść swoją bibliotekę gdzieś poza katalogami man lib i uruchom:

LD_PRELOAD='mylibc.so anotherlib.so' program

Zobacz: artykuł w Wikipedii

PiedPiper
źródło
1
pomyślałem, że to byłoby fajne obejście dla złożonego pliku Makefile, ale nie zadziałało
galactica
jest to przydatne zwłaszcza w przypadku braku kodu binarnego. dzięki
koder
2
um ... myliłem się, wygląda na to, że potrzebuję rpath do ld-linux.so do / path / to / new / lib / frist podczas kompilacji źródła i linkowania
koder
1
To nie działa, jeśli ld - #. ##. Więc (z twojego systemowego glibc lib) nie jest tą samą wersją glibc co libc.so. # (z twojej alternatywnej biblioteki glibc)
Andy
12

Przede wszystkim najważniejszą zależnością każdego dynamicznie połączonego programu jest linker. Wszystkie biblioteki muszą być zgodne z wersją konsolidatora.

Weźmy prosty przykład: mam nowy system ubuntu, w którym uruchamiam jakiś program (w moim przypadku jest to kompilator D - ldc2). Chciałbym go uruchomić na starym CentOS, ale ze względu na starszą bibliotekę glibc jest to niemożliwe. mam

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)

Muszę skopiować wszystkie zależności z Ubuntu do Centos. Właściwa metoda jest następująca:

Najpierw sprawdźmy wszystkie zależności:

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 nie jest prawdziwą biblioteką i nie musimy się tym przejmować.

/lib64/ld-linux-x86-64.so.2 to konsolidator, który jest używany przez linux do łączenia pliku wykonywalnego ze wszystkimi bibliotekami dynamicznymi.

Reszta plików to prawdziwe biblioteki i wszystkie razem z linkerem muszą zostać skopiowane gdzieś w centos.

Załóżmy, że wszystkie biblioteki i konsolidator znajdują się w katalogu „/ mylibs”.

ld-linux-x86-64.so.2 - jak już powiedziałem - jest konsolidatorem. To nie jest biblioteka dynamiczna, ale statyczny plik wykonywalny. Możesz go uruchomić i zobaczyć, że ma nawet kilka parametrów, np. --Library-path (wrócę do tego).

W Linuksie dynamicznie linkowany program może być uruchamiany tylko po jego nazwie, np

/bin/ldc2

Linux ładuje taki program do pamięci RAM i sprawdza, który konsolidator jest dla niego ustawiony. Zwykle w systemie 64-bitowym jest to /lib64/ld-linux-x86-64.so.2 (w twoim systemie plików jest to symboliczne łącze do rzeczywistego pliku wykonywalnego). Następnie linux uruchamia linker i ładuje biblioteki dynamiczne.

Możesz też trochę to zmienić i zrobić taką sztuczkę:

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

Jest to metoda wymuszenia na Linuksie użycia określonego konsolidatora.

A teraz możemy wrócić do wspomnianego wcześniej parametru --library-path

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

Uruchomi ldc2 i załaduje biblioteki dynamiczne z / mylibs.

Jest to metoda wywoływania pliku wykonywalnego z wybranymi (nie domyślnymi systemowymi) bibliotekami.

Arkadiusz Rychliński
źródło
Skompilowałem program na RH7 i potrzebuję go do działania na RH6. Nie chciałem budować nowego pliku wykonywalnego ani używać patchelf, więc jest to świetna alternatywa.
Mark Rajcok
9

Konfiguracja 1: skompiluj własną bibliotekę glibc bez dedykowanego GCC i używaj jej

Ta konfiguracja może działać i jest szybka, ponieważ nie rekompiluje ponownie całego zestawu narzędzi GCC, tylko glibc.

Ale to nie jest wiarygodne, ponieważ korzysta gospodarz C Runtime obiektów takich jak crt1.o, crti.oi crtn.odostarczane przez glibc. Wspomina się o tym pod adresem : https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Te obiekty wykonują wczesną konfigurację, na której opiera się glibc, więc nie zdziwiłbym się, gdyby coś się zawiesiło i niesamowicie subtelne sposoby.

Aby uzyskać bardziej niezawodną konfigurację, zobacz Konfiguracja 2 poniżej.

Skompiluj glibc i zainstaluj lokalnie:

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`

Konfiguracja 1: sprawdź kompilację

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);
}

Skompiluj i uruchom z 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

Program daje oczekiwane:

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

Polecenie zaadaptowano z https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location, ale --sysrootzawiodło:

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

więc go usunąłem.

ldddane wyjściowe potwierdzają, że lddbiblioteki i, które właśnie zbudowaliśmy, są używane zgodnie z oczekiwaniami:

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

Wynik gccdebugowania kompilacji pokazuje, że zostały użyte moje obiekty wykonawcze hosta, co jest złe, jak wspomniano wcześniej, ale nie wiem, jak to obejść, np. Zawiera:

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

Konfiguracja 1: zmodyfikuj glibc

Teraz zmodyfikujmy glibc za pomocą:

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)");

Następnie ponownie skompiluj i ponownie zainstaluj glibc oraz ponownie skompiluj i ponownie uruchom nasz program:

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

i widzimy hackedwydrukowane kilka razy zgodnie z oczekiwaniami.

To dodatkowo potwierdza, że ​​faktycznie używaliśmy skompilowanego glibc, a nie hosta.

Testowane na Ubuntu 18.04.

Konfiguracja 2: nieskazitelna konfiguracja crosstool-NG

Jest to alternatywa dla konfiguracji 1, i to jest najbardziej poprawna konfiguracja Mam osiągnąć daleko: wszystko jest w porządku o ile mogę obserwować, w tym C wykonywania obiektów, takich jak crt1.o, crti.oicrtn.o .

W tej konfiguracji skompilujemy w pełni dedykowany łańcuch narzędzi GCC, który używa potrzebnego glibc.

Jedyną wadą tej metody jest to, że kompilacja potrwa dłużej. Ale nie ryzykowałbym konfiguracji produkcyjnej z czymś mniejszym.

crosstool-NG to zestaw skryptów, które pobierają i kompilują wszystko ze źródła dla nas, w tym GCC, glibc i binutils.

Tak, system kompilacji GCC jest tak zły, że potrzebujemy do tego osobnego projektu.

Ta konfiguracja nie jest idealna tylko dlatego, że crosstool-NG nie obsługuje budowania plików wykonywalnych bez dodatkowych -Wlflag , co wydaje się dziwne, ponieważ stworzyliśmy samo GCC. Ale wydaje się, że wszystko działa, więc jest to tylko niedogodność.

Pobierz crosstool-NG, skonfiguruj i zbuduj:

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`

Budowa trwa od około trzydziestu minut do dwóch godzin.

Jedyną obowiązkową opcją konfiguracyjną, jaką widzę, jest dopasowanie do wersji jądra hosta, aby używać poprawnych nagłówków jądra. Znajdź wersję jądra hosta za pomocą:

uname -a

co pokazuje mi:

4.15.0-34-generic

więc w menuconfig robię:

  • Operating System
    • Version of linux

więc wybieram:

4.14.71

która jest pierwszą równą lub starszą wersją. Musi być starszy, ponieważ jądro jest kompatybilne wstecz.

Konfiguracja 2: opcjonalne konfiguracje

Ten .config, który wygenerowaliśmy, ./ct-ng x86_64-unknown-linux-gnuma:

CT_GLIBC_V_2_27=y

Aby to zmienić, menuconfigwykonaj:

  • C-library
  • Version of glibc

zapisz plik .configi kontynuuj tworzenie.

Lub, jeśli chcesz użyć własnego źródła glibc, np. Użyć glibc z najnowszego gita, postępuj w ten sposób :

  • Paths and misc options
    • Try features marked as EXPERIMENTAL: ustawione na true
  • C-library
    • Source of glibc
      • Custom location: Powiedz tak
      • Custom location
        • Custom source location: wskazuje katalog zawierający twoje źródło glibc

gdzie glibc został sklonowany jako:

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

Konfiguracja 2: przetestuj

Po zbudowaniu odpowiedniego łańcucha narzędzi przetestuj go za pomocą:

#!/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

Wygląda na to, że wszystko działa tak, jak w Instalatorze 1, z wyjątkiem tego, że teraz zostały użyte poprawne obiekty wykonawcze:

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

Instalacja 2: nieudana próba wydajnej ponownej kompilacji glibc

Nie wydaje się to możliwe w przypadku crosstool-NG, jak wyjaśniono poniżej.

Jeśli po prostu przebudujesz;

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

wtedy twoje zmiany w niestandardowej lokalizacji źródłowej glibc są brane pod uwagę, ale buduje wszystko od zera, przez co nie nadaje się do iteracyjnego rozwoju.

Jeśli zrobimy:

./ct-ng list-steps

daje ładny przegląd kroków kompilacji:

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.

dlatego widzimy, że istnieją kroki glibc przeplatane z kilkoma krokami GCC, w szczególności libc_start_fileswystępuje wcześniej cc_core_pass_2, co jest prawdopodobnie najdroższym krokiem razem zcc_core_pass_1 .

Aby zbudować tylko jeden krok, musisz najpierw ustawić .configopcję „Zapisz kroki pośrednie” dla początkowej kompilacji:

  • Paths and misc options
    • Debug crosstool-NG
      • Save intermediate steps

a potem możesz spróbować:

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

ale niestety +wymagane, jak wspomniano na: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536

Należy jednak pamiętać, że ponowne uruchomienie w kroku pośrednim powoduje zresetowanie katalogu instalacyjnego do stanu, jaki miał podczas tego kroku. Oznacza to, że będziesz mieć przebudowaną bibliotekę libc - ale nie będzie ostatecznego kompilatora zbudowanego z tą biblioteką (i stąd też nie będzie żadnych bibliotek kompilatorów takich jak libstdc ++).

i zasadniczo nadal sprawia, że ​​przebudowa jest zbyt wolna, aby była możliwa do opracowania, i nie widzę, jak to przezwyciężyć bez łatania crosstool-NG.

Co więcej, rozpoczęcie od libckroku nie Custom source locationpowodowało ponownego kopiowania źródła z , co dodatkowo czyniło tę metodę bezużyteczną.

Bonus: stdlibc ++

Bonus, jeśli interesuje Cię również standardowa biblioteka C ++: Jak edytować i przebudowywać standardowe źródło biblioteki GCC libstdc ++ C ++?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
6

Czy możesz rozważyć użycie Nix http://nixos.org/nix/ ?

Nix obsługuje zarządzanie pakietami dla wielu użytkowników: wielu użytkowników może bezpiecznie współużytkować wspólny sklep Nix, nie muszą mieć uprawnień roota do instalowania oprogramowania i mogą instalować i używać różnych wersji pakietu.


źródło
4

@msb zapewnia bezpieczne rozwiązanie.

Spotkałem się z tym problemem, gdy robiłem import tensorflow as tfw środowisku conda, w CentOS 6.5którym tylko miałem glibc-2.12.

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

Chcę podać kilka szczegółów:

Najpierw zainstaluj glibcw swoim katalogu domowym:

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

Po drugie, postępuj w ten sam sposób, aby zainstalować patchelf ;

Po trzecie, załataj swój 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

jak wspomniano w @msb

Teraz mogę używać tensorflow-2.0 alphaw CentOS 6.5.

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

Pasować
źródło
2

Nie jestem pewien, czy pytanie jest nadal aktualne, ale istnieje inny sposób rozwiązania problemu: Docker. Można zainstalować prawie pusty kontener dystrybucji źródłowej (dystrybucja używana do rozwoju) i skopiować pliki do kontenera. W ten sposób nie musisz tworzyć systemu plików potrzebnego do chroot.

user1396055
źródło
1

Jeśli przyjrzysz się uważnie drugiemu wynikowi, zobaczysz, że używana jest nowa lokalizacja bibliotek. Być może nadal brakuje bibliotek, które są częścią glibc.

Myślę też, że wszystkie biblioteki używane przez twój program powinny być skompilowane z tą wersją glibc. Jeśli masz dostęp do kodu źródłowego programu, najlepszym rozwiązaniem wydaje się nowa kompilacja.

rsarro
źródło
1

„Rosyjski zatrudniony” jest jedną z najlepszych odpowiedzi i myślę, że wszystkie inne sugerowane odpowiedzi mogą nie działać. Powodem jest po prostu to, że kiedy aplikacja jest tworzona po raz pierwszy, wszystkie jej potrzebne interfejsy API są rozwiązywane w czasie kompilacji. Używając "ldd" u możesz zobaczyć wszystkie statycznie połączone zależności:

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)

Jednak w czasie wykonywania firefox załaduje również wiele innych bibliotek dynamicznych, np. (Dla firefoxa) jest załadowanych wiele bibliotek z etykietą „glib” (mimo że statycznie nie ma żadnych):

 /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

Często można zobaczyć, że nazwy jednej wersji są połączone miękko z inną wersją. Na przykład:

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

Oznacza to zatem, że w jednym systemie istnieją różne wersje „bibliotek” - co nie stanowi problemu, ponieważ jest to ten sam plik, i zapewni zgodność, gdy aplikacje mają zależności między wieloma wersjami.

Dlatego na poziomie systemu wszystkie biblioteki są prawie współzależne od siebie, a sama zmiana priorytetu ładowania bibliotek poprzez manipulowanie LD_PRELOAD lub LD_LIBRARY_PATH nie pomoże - nawet jeśli może się załadować, w czasie wykonywania nadal może się zawiesić.

http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc

Najlepszą alternatywą jest chroot (krótko wspomniany przez ER): ale w tym celu będziesz musiał odtworzyć całe środowisko, w którym znajduje się oryginalny plik binarny - zwykle zaczynając od / lib, / usr / lib /, / usr / lib / x86 itp. Możesz użyć „Buildroot”, YoctoProject lub po prostu tarować z istniejącego środowiska Distro. (jak Fedora / Suse itp.).

Peter Teoh
źródło
0

Kiedy chciałem uruchomić przeglądarkę chromium na Ubuntu precyzyjne (glibc-2.15), otrzymałem (typowy) komunikat „... libc.so.6: wersja` GLIBC_2.19 'nie została znaleziona ... ”. Wziąłem pod uwagę fakt, że pliki nie są potrzebne na stałe, ale tylko na początek. Więc zebrałem pliki potrzebne dla przeglądarki i sudo i stworzyłem środowisko mini-glibc-2.19-, uruchomiłem przeglądarkę i ponownie skopiowałem oryginalne pliki. Potrzebne pliki znajdują się w pamięci RAM, a oryginalny plik glibc jest taki sam.

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)

skrypt do uruchomienia przeglądarki:

#!/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
dudu
źródło