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
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! :)Odpowiedzi:
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:
Opcja
-rpath
konsolidatora sprawi, że program ładujący środowiska uruchomieniowego wyszuka biblioteki w programie/path/to/newglibc
(więc nie trzeba go ustawiaćLD_LIBRARY_PATH
przed uruchomieniem), a-dynamic-linker
opcja „upiecze” ścieżkę do poprawieniald-linux.so.2
w aplikacji.Jeśli nie możesz ponownie połączyć
myapp
aplikacji (np. Ponieważ jest to plik binarny innej firmy), nie wszystko jest stracone, ale staje się to trudniejsze. Jednym z rozwiązań jest ustawieniechroot
dla niego odpowiedniego środowiska. Inną możliwością jest użycie rtldi i edytora binarnego .źródło
-Wl,--dynamic-linker=file
(bierze dwa '-') działa tylko podczas kompilacji dla plików wykonywalnych ELF. Sprawdź/sbin/ldconfig -p | grep ld
patchelf
( nixos.org/patchelf.html ), które pozwala na modyfikację rpath i interpretera już skompilowanego ELF.-Wl,--rpath
a nieLD_LIBRARY_PATH
może być ważne z powodów innych niż wygoda: jeśli program uruchamia procesy potomne, wartośćLD_LIBRARY_PATH
bę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 binarnymibash
), nie zostaną uruchomione./path/to/newglibc/ld-linux.so.2 --library-path /path/tonewglibc/lib64:/path/to/newglibc/usr/lib64 /path/to/myapp
-I
i-L
: stackoverflow.com/a/52454603/895245To 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:
A potem możesz po prostu uruchomić swój plik:
Na
chroot
szczęś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ącstrings
: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
myapp
korzysta, więc wiemy, że możemypatchelf
uż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:
Jeśli problem dotyczy bibliotek, polecenia, które podadzą używane biblioteki, to:
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 invalid
można to naprawić, ustawiając nowy program ładujący (--set-interpreter
część polecenia), jak wyjaśnię tutaj . Innym przykładem jest problem z pobieraniemNo such file or directory
po 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!
źródło
patchelf
), ale fraza „Nie ma potrzeby ... edycji plików binarnych” może być trochę myląca (ponieważ faktycznie edytujesz pliki binarne).Użyj LD_PRELOAD: umieść swoją bibliotekę gdzieś poza katalogami man lib i uruchom:
Zobacz: artykuł w Wikipedii
źródło
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
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:
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
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ę:
Jest to metoda wymuszenia na Linuksie użycia określonego konsolidatora.
A teraz możemy wrócić do wspomnianego wcześniej parametru --library-path
Uruchomi ldc2 i załaduje biblioteki dynamiczne z / mylibs.
Jest to metoda wywoływania pliku wykonywalnego z wybranymi (nie domyślnymi systemowymi) bibliotekami.
źródło
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.o
icrtn.o
dostarczane 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:
Konfiguracja 1: sprawdź kompilację
test_glibc.c
Skompiluj i uruchom z
test_glibc.sh
:Program daje oczekiwane:
Polecenie zaadaptowano z https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location, ale
--sysroot
zawiodło:więc go usunąłem.
ldd
dane wyjściowe potwierdzają, żeldd
biblioteki i, które właśnie zbudowaliśmy, są używane zgodnie z oczekiwaniami:Wynik
gcc
debugowania 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:Konfiguracja 1: zmodyfikuj glibc
Teraz zmodyfikujmy glibc za pomocą:
Następnie ponownie skompiluj i ponownie zainstaluj glibc oraz ponownie skompiluj i ponownie uruchom nasz program:
i widzimy
hacked
wydrukowane 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.o
icrtn.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
-Wl
flag , 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:
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ą:
co pokazuje mi:
więc w
menuconfig
robię:Operating System
Version of linux
więc wybieram:
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-gnu
ma:Aby to zmienić,
menuconfig
wykonaj:C-library
Version of glibc
zapisz plik
.config
i 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 trueC-library
Source of glibc
Custom location
: Powiedz takCustom location
Custom source location
: wskazuje katalog zawierający twoje źródło glibcgdzie glibc został sklonowany jako:
Konfiguracja 2: przetestuj
Po zbudowaniu odpowiedniego łańcucha narzędzi przetestuj go za pomocą:
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:
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;
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:
daje ładny przegląd kroków kompilacji:
dlatego widzimy, że istnieją kroki glibc przeplatane z kilkoma krokami GCC, w szczególności
libc_start_files
występuje wcześniejcc_core_pass_2
, co jest prawdopodobnie najdroższym krokiem razem zcc_core_pass_1
.Aby zbudować tylko jeden krok, musisz najpierw ustawić
.config
opcję „Zapisz kroki pośrednie” dla początkowej kompilacji:Paths and misc options
Debug crosstool-NG
Save intermediate steps
a potem możesz spróbować:
ale niestety
+
wymagane, jak wspomniano na: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536i 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
libc
kroku nieCustom source location
powodował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 ++?
źródło
Czy możesz rozważyć użycie Nix http://nixos.org/nix/ ?
źródło
@msb zapewnia bezpieczne rozwiązanie.
Spotkałem się z tym problemem, gdy robiłem
import tensorflow as tf
w środowisku conda, wCentOS 6.5
którym tylko miałemglibc-2.12
.Chcę podać kilka szczegółów:
Najpierw zainstaluj
glibc
w swoim katalogu domowym:Po drugie, postępuj w ten sam sposób, aby zainstalować patchelf ;
Po trzecie, załataj swój Python:
jak wspomniano w @msb
Teraz mogę używać
tensorflow-2.0 alpha
wCentOS 6.5
.ref: https://serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/
źródło
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.
źródło
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.
źródło
„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:
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):
Często można zobaczyć, że nazwy jednej wersji są połączone miękko z inną wersją. Na przykład:
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.).
źródło
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.
mkdir -p /glibc-2.19/i386-linux-gnu
mkdir -p /glibc-2.15/i386-linux-gnu
skrypt do uruchomienia przeglądarki:
źródło