На моем сервере linux (SLES-8) сейчас есть glibc-2.2.5-235, но у меня есть программа, которая не работает в этой версии и требует glibc-2.3.3.
Возможно ли установить несколько glibc на одном хосте?
Это ошибка, которую я получаю, когда запускаю свою программу на старом 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)
Итак, я создал новый каталог с именем newglibc и скопировал в него следующие файлы:
libpthread.so.0
libm.so.6
libc.so.6
ld-2.3.3.so
ld-linux.so.2 -> ld-2.3.3.so
а также:
export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH
Но получаю ошибку:
./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)
Таким образом, получается, что они все еще ссылаются на /lib и не подхватываются с того места, где я их разместил.
Ответ 1
Возможно иметь несколько версий glibc в одной системе.
Однако вам нужно знать, что glibc состоит из множества частей (более 200 разделяемых библиотек), которые все должны совпадать. Одна из частей — ld-linux.so.2, и она должна соответствовать libc.so.6, иначе вы увидите ошибки, которые появляются у вас.
Абсолютный путь к ld-linux.so.2 жестко запрограммирован в исполняемый файл и не может быть легко изменен после создания ссылки.
Чтобы создать исполняемый файл, который будет работать с новым glibc, сделайте следующее:
g++ main.o -o myapp ... \
-Wl,--rpath=/path/to/newglibc \
-Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2
Параметр -rpath компоновщика заставит загрузчик времени выполнения искать библиотеки /path/to/newglibc (так что вам не нужно будет устанавливать его в LD_LIBRARY_PATH перед запуском), а параметр -dynamic-linker «внедрит» путь для исправления ld-linux.so.2 в приложении.
Если вы не можете повторно связать приложение (например, потому что это сторонний двоичный файл), не все потеряно, но становится сложнее. Одно из решений — создать для него подходящую chroot среду. Другая возможность — использовать rtldi и двоичный редактор. Также можно использовать patchelf.
Ответ 2
Этот довольно старая проблема. К счастью, в настоящее время у нас есть простое решение этой проблемы с использованием patchelf. Все, что вам нужно сделать, — это:
$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp
И после этого вы можете просто запустить свой файл:
$ ./myapp
В chroot нет необходимости вручную редактировать двоичные файлы. Но не забудьте сделать резервную копию вашего двоичного файла перед его исправлением, если вы не уверены, что делаете, потому что это изменяет ваш двоичный файл. После того, как вы его исправите, вы не сможете восстановить старый путь к интерпретатору/rpath. Если это не сработает, вам придется продолжать исправлять его, пока вы не найдете путь, который действительно будет работать… Что ж, это не обязательно должен быть процесс проб и ошибок. Например, в примере GLIBC_2.3 вы можете легко найти, какая библиотека предоставляет требуемую версию, используя strings:
$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3
Теоретически первый grep будет пустым, потому что системная libc не имеет нужной ему версии, а второй должен вывести GLIBC_2.3, потому что у него есть версия myapp, которая используется, поэтому мы знаем, что можем использовать patchelf для нашего двоичного файла, используя этот путь. Если вы столкнулись с ошибкой сегментации, прочтите примечание в конце.
Когда вы пытаетесь запустить двоичный файл в Linux, двоичный файл пытается загрузить компоновщик, а затем библиотеки, и все они должны быть в пути и/или в нужном месте. Если ваша проблема связана с компоновщиком и вы хотите узнать, какой путь ищет ваш двоичный файл, вы можете определить это с помощью команды:
$ readelf -l myapp | grep interpreter
[Требуется программный интерпретатор: /lib/ld-linux.so.2]
Если ваша проблема связана с библиотеками, команды, которые предоставят вам используемые библиотеки:
$ readelf -d myapp | grep Shared
$ ldd myapp
Это перечислит библиотеки, которые нужны вашему двоичному файлу, но вы, вероятно, уже знаете проблемные, поскольку они уже вызывают ошибки.
«patchelf» решает множество различных проблем, с которыми вы можете столкнуться при попытке запустить программу, связанную с этими двумя проблемами. Например, если вы получите ошибку: ELF file OS ABI invalid —это можно исправить, установив новый загрузчик ( --set-interpreter часть команды). Другой пример — проблема получения ошибки No such file or directory при запуске файла. В этом конкретном случае отсутствовала ссылка на загрузчик, но, возможно, в вашем случае у вас нет root-доступа и вы не можете создать ссылку. Установка нового интерпретатора решит вашу проблему.
Примечание для ошибки сегментации: возможно, ваш myapp использует несколько библиотек, и большинство из них в порядке, а некоторые — нет; затем в patchelf вы переходите в новый каталог и получаете ошибку сегментации. Когда вы используете в patchelf свой двоичный файл, вы меняете путь к нескольким библиотекам, даже если некоторые из них изначально находились по другому пути. Взгляните на мой пример ниже:
$ ldd myapp
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version "GLIBCXX_3.4.20" not found (required by ./myapp)
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version "GLIBCXX_3.4.21" not found (required by ./myapp)
linux-vdso.so.1 => (0x00007fffb167c000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a9aad2000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a9a8ce000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a9a6af000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9a9a3ab000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a99fe6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9a9adeb000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9a99dcf000)
Обратите внимание, что большинство библиотек уже есть, /lib/x86_64-linux-gnu/, но проблемная (libstdc++.so.6) включена /usr/lib/x86_64-linux-gnu. После того, как я установил патч для myapp, чтобы указать ей путь /path/to/mylibs, у меня возникла ошибка сегментации. По какой-то причине библиотеки не полностью совместимы с двоичным файлом. Так как myapp не жаловался на оригинальной LIBS, я скопировал их из /lib/x86_64-linux-gnu/ по пути /path/to/mylibs2, и libstdc++.so.6 из /path/to/mylibs. Затем я пропатчил его из /path/to/mylibs2, и теперь все работает. Если ваш двоичный файл использует разные библиотеки и у вас разные версии, может случиться так, что вы не сможете исправить эту ситуацию. Но если это возможно, смешайте библиотеки. Это не идеально, но, возможно, это сработает. Удачи!
Ответ 3
Прежде всего, наиболее важной зависимостью каждой динамически связанной программы является компоновщик. Все библиотеки должны соответствовать версии компоновщика.
Возьмем простой пример: у меня есть система newset ubuntu, в которой я запускаю какую-то программу (в моем случае это компилятор D — ldc2). Я бы хотел запустить его на старой CentOS, но из-за старой библиотеки glibc это невозможно. Я получил:
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)
Мне нужно скопировать все зависимости с ubuntu на centos. Правильный метод следующий:
Сначала проверим все зависимости:
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 — это не настоящая библиотека, и нам не нужно о ней заботиться.
/lib64/ld-linux-x86-64.so.2 — это компоновщик, который используется Linux и связывает исполняемый файл со всеми динамическими библиотеками.
Остальные файлы являются настоящими библиотеками, и все они вместе с компоновщиком должны быть скопированы где-нибудь в centos.
Предположим, что все библиотеки и компоновщик находятся в каталоге «/mylibs».
ld-linux-x86-64.so.2, как я уже сказал, является компоновщиком. Это не динамическая библиотека, а статический исполняемый файл. Вы можете запустить его и увидеть, что у него даже есть некоторые параметры, например, --library-.
В Linux динамически скомпонованная программа может запускаться только по ее имени, например:
/bin/ldc2
Linux загружает такую программу в RAM и проверяет, какой компоновщик для нее установлен. Обычно в 64-битной системе это /lib64/ld-linux-x86-64.so.2 (в вашей файловой системе это символическая ссылка на реальный исполняемый файл). Затем Linux запускает компоновщик и загружает динамические библиотеки.
Вы также можете немного изменить это и проделать такой трюк:
/mylibs/ld-linux-x86-64.so.2 /bin/ldc2
Это метод заставляет Linux использовать определенный компоновщик.
А теперь мы можем вернуться к упомянутому ранее параметру --library-path
/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2
Он запустит ldc2 и загрузит динамические библиотеки из /mylibs.
Это метод вызова исполняемого файла с выбранными (не системными по умолчанию) библиотеками.
Linux