Найти в Дзене

Запуск современных программ на устаревшем дистрибутиве Linux

Оглавление
ИГОРЬ ОРЕЩЕНКОВ, инженер-программист, iharsw@tut.by
ИГОРЬ ОРЕЩЕНКОВ, инженер-программист, iharsw@tut.by

На примере неподдерживаемого дистрибутива Linux и современного веб-браузера приводятся сведения, необходимые для создания среды выполнения приложений, требующих альтернативных версий системных библиотек

Быстрое развитие информационных технологий приводит к тому, что одно за другим сменяются поколения аппаратных платформ, а программные продукты стараются не отставать в этой гонке. Однако реальность такова, что устаревшие версии операционных систем продолжают эксплуатироваться. Причины этого могут лежать в нескольких плоскостях:

  • экономической – отсутствие средств на модернизацию вычислительной техники;
  • технологической – нужная программа работает только на конкретной версии операционной системы;
  • психологической – пользователь привык к используемому программному обеспечению, которое он хорошо изучил и функциональность которого его полностью устраивает.

В этой статье на примере популярного в свое время дистрибутива Mandriva Linux 2008 рассматриваются действия, необходимые для запуска современного веб-браузера Pale Moon.

Исследование проблемы

Получить современный веб-браузер на устаревшем Linux можно как минимум двумя способами:

  • Адаптировать исходные тексты веб-браузера для работы с пакетами тех версий, которые имеются в дистрибутиве.
  • Создать в установленной системе среду, которая требуется для выполнения веб-браузера.

Первый путь – самый эстетичный, но практически неосуществимый. Веб-браузер представляет собой сложный комплекс модулей, в котором каждый модуль – это отдельный проект, разработкой которого занимается независимая команда. И если разработчики приняли решение об отказе от поддержки устаревших версий операционных систем, выполнять эту работу за них чрезвычайно сложно.

Создадим требуемую среду выполнения и избежим конфликтов различных версий динамических библиотек

Второй путь более реалистичный, тем более что он допускает два подхода:

  • Обновить пакеты дистрибутива, которые не удовлетворяют требованиям современных веб-браузеров.
  • Установить требуемые пакеты в качестве дополнительных и сконфигурировать веб-браузер на их использование.

Следование первому подходу может негативно отразиться на стабильности операционной системы, поскольку официальные обновления для дистрибутива уже не выпускаются, а провести всеобъемлющее тестирование системы с собранными самостоятельно пакетами практически так же сложно, как адаптировать браузер к системе.

При использовании второго подхода устанавливаемое программное обеспечение будет взаимодействовать только с веб-браузером, и стабильность системы не пострадает. В статье предпочтение отдано именно этому, более безопасному, подходу.

Динамически компонуемые программы

Программы в машинных кодах, предназначенные для выполнения в операционной системе Linux, при сборке из исходных текстов могут быть скомпонованы с вспомогательными библиотеками статически или динамически [1].

За загрузку динамически компонуемых программ (см. рис. 1) в операционной системе отвечает загрузчик, ссылка на который находится в файле /lib/ld-linux.so.2. Сам загрузчик скомпонован статически, в чем можно убедиться с помощью команды:

$ file /lib/ld-2.6.1.so

/lib/ld-2.6.1.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped

Рисунок 1. Структура файла динамически компонуемой программы и варианты поиска связанных динамических библиотек
Рисунок 1. Структура файла динамически компонуемой программы и варианты поиска связанных динамических библиотек

Для динамически компонуемых программ вывод команды file содержит текст dynamically linked (uses shared libs), например:

$ file palemoon/palemoon

$ palemoon/palemoon: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.18, dynamically linked (uses shared libs), stripped

Посмотреть, от каких конкретно динамических библиотек зависит исполняемый файл, можно с помощью команды:

$ ldd palemoon/palemoon

linux-gate.so.1 => (0xffffe000)
libpthread.so.0 => /lib/i686/libpthread.so.0 (0xb7f6d000)
libdl.so.2 => /lib/libdl.so.2 (0xb7f69000)
librt.so.1 => /lib/i686/librt.so.1 (0xb7f60000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e72000)
libm.so.6 => /lib/i686/libm.so.6 (0xb7e4d000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7e41000)
libc.so.6 => /lib/i686/libc.so.6 (0xb7d00000)
/lib/ld-linux.so.2 (0xb7f96000)

Перед выполнением динамически компонуемой программы загрузчик должен:

  • загрузить код программы в оперативную память;
  • отыскать файлы динамических библиотек и загрузить код модулей в оперативную память;
  • исправить в загруженном коде программы ссылки на динамические модули в соответствии с их фактическим местонахождением.

По умолчанию поиск динамических библиотек, необходимых для работы программы, производится в следующем порядке (man 8 ld.so):

  • в местах, указанных при компиляции программ;
  • в каталогах, перечисленных в конфигурационном файле /etc/ld.so.conf, сведения из которого обрабатываются системной утилитой ldconfig и вносятся в файл двоичного формата /etc/ld.so.cache;
  • в стандартных системных каталогах /usr/lib и /lib.

Временно описанный порядок поиска можно изменить, указав приоритетные пути в переменной окружения LD_LIBRARY_PATH:

$ env LD_LIBRARY_PATH=$HOME/usr/lib palemoon/palemoon

Заметим, что пути, которые указаны в п. 3, записаны в файл загрузчика при его компиляции. В этом можно легко убедиться:

$ strings /lib/ld-2.6.1.so | grep /lib

/lib/
/usr/lib/

При сборке пакета glibc из исходных текстов для установки в нестандартном каталоге эти пути могут быть другими, что будет показано в дальнейшем.

Веб-браузер Pale Moon

Загрузим с официального веб-сайта 32-битную версию веб-браузера Pale Moon, распакуем дистрибутивный архив и попробуем его выполнить:

$ tar jxf palemoon-28.1.0.linux-i686.tar.bz2
$ palemoon/palemoon

XPCOMGlueLoad error for file $HOME/palemoon/libxul.so:
/home/ussr/palemoon/libxul.so: ELF file OS ABI invalid
Couldn't load XPCOM.

Браузер не запустился, а из полученного сообщения становится понятно, что ошибка произошла при инициализации системы XPCOM. Сообщение ELF file OS ABI invalid характерно для подсистемы glibc, когда загрузчик динамических библиотек (/lib/ld-linux.so.2) не может идентифицировать интерфейс динамической библиотеки (в данном случае libxul.so).

Причиной подобной проблемы зачастую является:

  • несоответствие версии динамической библиотеки архитектуре операционной системы (в том числе попытка использования 64-битных динамических библиотек на 32-битных операционных системах);
  • несоответствие версии подсистемы glibc, установленной в операционной системе, той, которая необходима для выполнения программы.

Посмотрим сведения о динамических библиотеках пакета palemoon:

$ file -L palemoon/*.so

( . . . )
palemoon/libsmime3.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), stripped
palemoon/libsoftokn3.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), stripped
palemoon/libssl3.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), stripped
palemoon/libxul.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), stripped

Обнаружено различие в параметре OS ABI библиотеки palemoon/libxul.so (GNU/Linux) и остальных динамических библиотек (SYSV).

Спецификация SYSV традиционна для формата ELF и операционных систем семейства UNIX, тогда как соглашение OS ABI GNU/Linux было введено позже. К сожалению, загрузчик динамических библиотек, являющийся компонентом установленной в операционной системе подсистемы glibc, не смог распознать этот формат и сообщил об ошибке.

Решить возникшую проблему можно двумя способами:

  • Обновить подсистему glibc используемого дистрибутива.
  • Отыскать подходящую версию проблемной динамической библиотеки в поддерживаемом формате.

Второй способ проще в случае удачного поиска, но в долгосрочной перспективе может вызвать проблемы. Ведь выполняться будет уже не исходный, а модифицированный пакет веб-браузера, и после планового обновления его до новой версии может потребоваться повторная замена динамической библиотеки. Поэтому соберем подсистему glibc из исходных текстов.

Подготовка сред выполнения и сборки

Для решения поставленной в статье задачи решено задействовать три области размещения бинарных файлов (см. рис. 2):

  • Штатные библиотеки дистрибутива /lib/usr/lib и его исполняемые файлы /bin/sbin/usr/bin/usr/sbin.
  • Дополнительные библиотеки $HOME/usr/lib и исполняемые файлы $HOME/usr/bin$HOME/usr/sbin, зависимости которых не выходят за рамки этих дополнительных библиотек и стандартных библиотек из п. 1.
  • Новая версия библиотеки glibc и зависящие от нее библиотеки $HOME/glibc-2.16/lib, а также связанные с этими библиотеками исполняемые файлы $HOME/glibc-2.16/bin и $HOME/glibc-2.16/sbin.
Рисунок 2. Схема размещения файловых областей программ с динамическими библиотеками и исходных текстов с результатами сборки
Рисунок 2. Схема размещения файловых областей программ с динамическими библиотеками и исходных текстов с результатами сборки

Необходимость выделения библиотеки glibc 2.16 и зависимых от нее программ в отдельный каталог по отношению к $HOME/usr связана с существенными трудностями при конфигурировании среды сборки пакетов, зависящих от штатных библиотек дистрибутива и некоторых дополнительных библиотек (см. приложение 1). Спрятать новую версию glibc от средств разработки проще всего таким организационным методом, нежели задавать массу ключей для компилятора и компоновщика.

Файлы с исходными текстами для сборки пакетов программного обеспечения размещаются в каталоге $HOME/work. В нем создан подкаталог $HOME/work/obj для промежуточного хранения результатов сборки GCC и glibc.

Дело в том, что если большинство пакетов могут быть собраны с помощью классической последовательности команд:

./configure --prefix=$PREFIX; make; make install

выполненных из каталога с исходными текстами, то аналогичные команды для GCC и glibc должны выполняться из пустых подкаталогов.

Для подготовки среды сборки пакетов удобно использовать файл build.env с таким содержимым:

#!/bin/sh
PREFIX=$HOME/usr
PATH=$PREFIX/bin:$PATH
PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig
LD_LIBRARY_PATH=$PREFIX/lib:/lib:/usr/lib
export PKG_CONFIG_PATH LD_LIBRARY_PATH

Перед выполнением команд сборки этот файл нужно задействовать (однократно!) в сеансе терминала следующей командой:

$ source build.env

Подготовка инструментария

Основными инструментами разработки приложений в мире Linux являются компилятор GNU GCC и утилиты GNU BinutilsGNU Make и GNU Autoconf [2]. В дальнейшем изложении для сокращения текста префикс GNU будет опускаться.

Для решения задачи, поставленной в статье, нет необходимости в использовании утилит Autoconf, потому что исходные тексты всех задействованных пакетов доступны в виде версионированных tar-архивов. Версия установленной в дистрибутиве утилиты Make не вызвала никаких нареканий со стороны конфигурационных сценариев, поэтому тоже останется без изменений. Потребуется обновить лишь GCC и Binutils.

В первую очередь устанавливаются средства разработки, поставляемые дистрибутивом. Они объединены метапакетом kernel-desktop-devel-2.6.22-1mdv.

Отдельно устанавливается компилятор Си++, который представлен пакетом gcc-c++ 4.2.2-0.RC.1mdv2008.0. Если о нем забыть, то при сборке GCC будет выдано сообщение об ошибке:

configure: error: C++ compiler missing or inoperational

конфигуратор почему-то не обнаруживает этой проблемы, а для исправления ошибки надо удалить каталог с результатами частичной сборки, создать новый и после установки gcc-c++ заново выполнить конфигурирование.

Для сборки GCC в каталог с исходными текстами нужно распаковать вспомогательные пакеты точной и комплексной арифметики (ISLGMPMPFR и MPC) и создать в нем символические ссылки на версионированные папки:

$ ln -s mpc-1.0.3 mpc
$ ln -s mpfr-3.1.4 mpfr
$ ln -s isl-0.18 isl
$ ln -s gmp-6.1.0 gmp

Если не установить вспомогательные пакеты, то конфигурирование завершится с ошибкой:

configure: error: Building GCC requires GMP 4.2+, MPFR 2.4.0+ and MPC 0.8.0+.

Сборку GCC нельзя производить в том же каталоге, где находятся исходные тексты пакета. Поэтому в каталоге obj создается подкаталог gcc-4.8.2, делается текущим, и уже из него дается команда на конфигурирование:

$ ../../gcc-4.8.2/configure --prefix=$PREFIX --enable-languages=c,c++

Ограничение списка поддерживаемых языков программирования способствует уменьшению времени сборки и занимаемого дискового пространства. После конфигурирования сборка и установка GCC производятся с помощью команд:

make; make install

Сборка пакета binutils-2.24 производится по стандартной схеме, с указанием на этапе конфигурирования пути к целевому каталогу.

Сборка glibc

Основная роль библиотеки glibc – реализация интерфейса между функциями стандарта POSIX и системными вызовами ядра операционной системы. Поэтому она находится в сильной зависимости от ядра. Если, например, в среде дистрибутива Mandriva 2008 можно без особенных проблем собрать самую современную версию компилятора GCC 8.2, то к выбору совместимой версии glibc нужно подходить с большой осмотрительностью, ориентируясь на период расцвета ядра версии 2.6. В результате ряда экспериментов была найдена подходящая версия для модернизации – glibc-2.16.0.

Сборку glibc рекомендуется осуществлять с указанием на заголовочные файлы самой современной версии ядра операционной системы из доступных. В ретроспективе «современность» означает доступность на момент выпуска glibc, в рассматриваемом примере это версия 2.6.38.8 (попытка сборки антикварной версии glibc со ссылкой на заголовочные файлы ядра четвертой или даже третьей версии GNU/Linux ни к чему хорошему не приведет).

Для установки заголовочных файлов нужно распаковать архив с исходными текстами linux-2.6.38.8.tar.bz2, сделать создавшийся при этом каталог текущим и выполнить команды:

$ HEADERS=$HOME/work/kernel-2.6.38.8-headers
$ make headers_install arch=i686 INSTALL_HDR_PATH=$HEADERS

где значение переменной HEADERS задает целевой каталог для заголовочных файлов.

Для сборки пакета glibc, как и для GCC, нужно создать отдельный подкаталог obj/glibc-2.16.0 и сделать его текущим. После этого можно выполнять конфигурирование:

$ ../../glibc-2.16.0/configure --prefix=$HOME/glibc-2.16 i686-pc-linux CFLAGS='-O2 -march=i686' --with-headers=$HEADERS/include --enable-kernel=2.6.22

Параметр enable-kernel задает минимальную версию ядра, которая будет поддерживаться библиотекой glibc, а параметры, содержащие i686, позволяют произвести на современном компьютере сборку пакета для устаревшей архитектуры. Если в параметре with-headers указать неправильный путь, то конфигурирование может пройти успешно, но при сборке будет выведена серия сообщений об ошибках вида:

#include <.../... .h> Фатальная ошибка: .../... .h Нет такого файла или каталога

Если же в перечне флагов компилятора CFLAGS не указать опцию -O2, то сборка будет прервана ошибкой:

# error "glibc cannot be compiled without optimization"

Процесс сборки запускается командой:

$ make

Установка производится с помощью команды:

$ env LANGUAGE=C LC_ALL=C make install

Свежесобранный загрузчик динамически компонуемых программ в качестве стандартного пути поиска динамических библиотек будет использовать единственный каталог $HOME/glibc-2.16/lib, в чем легко убедиться:

$strings $HOME/glibc-2.16/lib/ld-2.16.so | grep /lib
$HOME/glibc-2.16/lib/

Поэтому теперь нужно создать файл $HOME/usr/etc/ld.so.conf с перечнем дополнительных путей поиска динамических библиотек:

/lib
/usr/lib
/usr/lib/vmware-tools/lib32/libgio-2.0.so.0

и выполнить команду индексирования перечисленных каталогов:

$ $HOME/usr/sbin/ldconfig.

Запуск программы с новой версией glibc

На данном этапе в системе установлены две версии glibc:

  • поставлявшаяся вместе с дистрибутивом 2.6.1 и находящаяся в каталоге /lib (с загрузчиком динамических библиотек /lib/ld-linux.so.2 -> /lib/ld-2.6.1.so);
  • новая 2.16.0, находящаяся в каталоге $HOME/glibc-2.16/lib (с загрузчиком динамических библиотек $HOME/glibc-2.16/lib/ld-linux.so.2 -> ld-2.16.0.so).

Если сейчас попытаться запустить веб-браузер командой:

$ env LD_LIBRARY_PATH=$HOME/glib-2.16/lib palemoon/palemoon

то будет выдано сообщение об ошибке:

palemoon/palemoon: error while loading shared libraries: $HOME/glib-2.16/lib/libm.so.6: ELF file OS ABI invalid

Дело в том, что при запуске программы palemoon/palemoon был задействован загрузчик динамических библиотек /lib/ld-2.6.1.so, которому не знаком новый формат динамической библиотеки libm.so.6. Система не применила новую версию загрузчика из $HOME/glib-2.16/lib/ld-2.16.0.so, потому что путь к загрузчику прописывается в исполняемом файле при компиляции и, как правило, представлен ссылкой /lib/ld-linux.so.2.

Для запуска программы с помощью конкретной версии загрузчика можно воспользоваться такой командой:

$HOME/glibc-2.16/lib/ld-linux.so.2 --library-path $HOME/glibc-2.16/lib:$HOME/usr/lib palemoon/palemoon

В параметре --library-path прописаны приоритетные пути поиска динамических библиотек. Теперь ошибка выглядит так:

XPCOMGlueLoad error for file /home/ussr/palemoon/libxul.so:
libX11-xcb.so.1: cannot open shared object file: No such file or directory
Couldn't load XPCOM.

Полученное сообщение говорит о том, что системе не удалось обнаружить файл динамической библиотеки libX11-xcb.so.1, который нужен модулю libxul.so. Это небольшая интерфейсная библиотека, которую проще всего взять в готовом двоичном виде для архитектуры i386 из дистрибутива Debian и записать файлы libX11-xcb.so.1 и libX11-xcb.so.1.0.0 в каталог $HOME/usr/lib. После этого попытка запуска веб-браузера palemoon прервется сообщением:

(pale moon:27834): Gtk-WARNING **: Locale not supported by C library.
Using the fallback 'C' locale.
palemoon/palemoon: symbol lookup error: /home/ussr/palemoon/libxul.so: undefined symbol: gdk_x11_set_sm_client_id

Ссылка на отсутствующий символ gdk_x11_set_sm_client_id говорит о том, что установленная в дистрибутиве версия библиотеки GTK+ 2.12 не соответствует минимальным требованиям веб-браузера относительно GTK+ >= 2.24. Выполним установку требуемой версии GTK+.

Сборка GTK+

С учетом изложенных выше сведений сборка пакета GTK+ 2.24 из исходных текстов превращается в рутинную процедуру. Желающие могут ее повторить, предварительно установив из дистрибутива следующие пакеты:

  • zlib1-devel 1.2.3-8mdv2008.0;
  • libpng-devel 1.2.19-2mdv2008.0;
  • libfreetype6-devel 2.3.5-2mdv2008.0;
  • libx11_6-devel 1.1.3-2mdv2008.0;
  • libxrandr2-devel 1.2.2-1 mdv2008.0.

Без последнего пакета конфигуратор GTK+ будет завершаться с сообщением об ошибке:

checking for XOpenDisplay... no
configure: error: *** libX11 not found. Check 'config.log' for more details.

Перед сборкой остальных пакетов нужно сконфигурировать среду (если она еще не была сконфигурирована) с помощью файла build.env, как было описано выше. Сборка выполняется посредством классической последовательности команд:

./configure --prefix=$PREFIX; make; make install

в соответствии с деревом зависимостей (см. приложение 2):

GTK+ [2.24.20]
glib-2.0 [2.34.3]
libffi [3.2.1]
gettext [0.18.3.2]
atk [2.8.0]
pango [1.30.1]
cairo [1.10.2]
pixman [0.32.4]
expat [2.1.0]
fontconfig [2.10.94]
gdk-pixbuf-2.0 [2.28.2]
libtiff [3.9.7]
libjpeg [9c]]

Если у платформы, на которой выполняется сборка, нет доступа к интернету, то при конфигурировании пакета glib-2.0 нужно отключить генерацию файлов документации, указав параметр --disable-man, во избежание ошибок:

GEN glib-gettextize.1
I/O error : Attempt to load network entity http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl
warning: failed to load external entity http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl
cannot parse http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl

После установки GTK+ веб-браузер palemoon-28.1 успешно запускается командой (см. рис. 3):

$ $HOME/glibc-2.16/lib/ld-linux.so.2 --library-path $HOME/glibc-2.16/lib:$HOME/usr/lib palemoon/palemoon &

Рисунок 3. Веб-браузер palemoon-28.1 запущен под управлением операционной системы Mandriva 2008 в созданном окружении
Рисунок 3. Веб-браузер palemoon-28.1 запущен под управлением операционной системы Mandriva 2008 в созданном окружении

Цель, поставленная в начале статьи, достигнута.

Запуск современных приложений может быть выполнен под управлением устаревших неподдерживаемых версий операционных систем (и наоборот), если для них будет создано необходимое окружение. С помощью приемов, которые описаны в этой статье, можно создать требуемую среду выполнения и избежать конфликтов различных версий динамических библиотек.

Приведем список тезисов, которыми предлагается руководствоваться при решении проблем, связанных с работой динамически компонуемых программ:

  • Для выполнения динамически компонуемых программ операционная система задействует загрузчик динамических библиотек.
  • Загрузчик динамических библиотек является частью пакета glibc и представляет собой статически скомпонованную программу.
  • Путь к загрузчику на этапе компиляции программы записывается в файл с е-двоичным кодом: /lib/ld-linux.so.2.
  • Для запуска программы альтернативным загрузчиком нужно выполнить сам загрузчик, передав ему в качестве параметров имя запускаемой программы и приоритетные пути поиска динамических библиотек.
  • Основные пути поиска динамических библиотек задаются в конфигурационном файле /etc/ld.so.conf, на основе которого с помощью команды:/sbin/ldconfig
    строится индексный файл 
    /etc/ld.so.cache, используемый загрузчиком.
  • Приоритетные пути поиска динамических библиотек могут быть заданы через переменную окружения PKG_CONFIG_PATH.
  • Приоритетный путь поиска runtime-библиотек, с которыми компилятор связывает код программы, может быть изменен с помощью опции компоновщика -rpath, которая может быть передана через переменную параметров компилятора в виде: CFLAGS='-Wl,-rpath,ПУТЬ'
  • Порядок обхода путей системой сборки в поисках динамических библиотек может быть изменен и дополнен посредством указания: CFLAGS='-L Путь1 -L Путь2'

Описанные в статье приемы и методы могут быть использованы для решения задачи запуска произвольных программ под различными операционными системами семейства Linux.

Приложение 1. Зачем нужно выделять glibc?

Возникает вопрос: «А нельзя ли для единообразия установить новую версию glibc в каталог $HOME/usr вместе со всеми дополнительными программами и библиотеками?» Давайте рассмотрим, с какими проблемами придется столкнуться при таком варианте и как их можно решать.

При сборке программы из исходных текстов компилятор записывает в исполняемый файл путь к каталогу, в котором загрузчик будет искать файлы библиотек времени выполнения (runtime libraries) в первую очередь. Как правило, это каталог $PREFIX/lib. Если при конфигурировании не указывать параметр --prefix, то в качестве $PREFIX будет использовано значение по умолчанию: /usr/local.

Во вновь установленном дистрибутиве каталог /usr/local/lib пуст, поэтому при запуске собранной из исходных текстов программы будет задействована библиотека /lib/libc.so.6 в соответствии с правилом поиска динамических библиотек.

Но в описываемой ситуации, когда программное обеспечение конфигурируется с параметром --prefix=$HOME/usr, при запуске исполняемых файлов будут подключаться динамические библиотеки из каталога $HOME/usr/lib, который содержит новую версию библиотеки glibc.

Это не всегда желательно. Если, например, в такой конфигурации собрать пакет xz-5.2.4, который необходим для распаковки xz-архивов, то при запуске утилиты xz будет выдаваться уже знакомая ошибка:

xz: error while loading shared libraries: $HOME/usr/lib/libc.so.6: ELF file OS ABI invalid

Привязки динамических библиотек можно увидеть с помощью команды:

$ $HOME/usr/lib/ld-linux.so.2 --list $HOME/usr/bin/xz

...
libc.so.6 => $HOME/usr/lib/libc.so.6 (0xb7de4000)
/lib/ld-linux.so.2 => $HOME/usr/lib/ld-linux.so.2 (0x80000000)

Причину произошедшего демонстрирует команда:

$ strings $HOME/usr/bin/xz | grep lib

/lib/ld-linux.so.2
...
libc.so.6
__libc_start_main
$HOME/usr/lib
liblzma %s

Чтобы такой ситуации избежать, нужно в команде конфигурирования указать приоритетные пути для поиска библиотек компоновщиком (man ld):

$ ./configure --prefix=$HOME/usr LDFLAGS='-Wl,-rpath,/lib'

После сборки утилита запускается и работает нормально благодаря компоновке с заданными версиями динамических библиотек:

$ ldd $HOME/usr/bin/xz

...
libc.so.6 => /lib/i686/libc.so.6 (0xb7df2000)
/lib/ld-linux.so.2 (0xb7f7f000)

Убедиться в результативности произведенной настройки можно с помощью команды:

$ strings $HOME/usr/bin/xz | grep lib

/lib/ld-linux.so.2
...
libc.so.6
__libc_start_main
/lib:$HOME/usr/lib
liblzma %s

При сборке из исходных текстов динамических библиотек (например, libffi-3.2.1, которая необходима пакету GTK+) можно столкнуться с проблемой иного рода. Новый компилятор GCC, установленный в каталог $HOME/usr/bin, обнаруживает новую версию библиотеки glibc и собирает целевую динамическую библиотеку с присвоением ей зависимости от версии новой библиотеки:

$ $HOME/usr/bin/ldd $HOME/usr/lib/libffi.so

$HOME/usr/lib/libffi.so: /lib/i686/libc.so.6: version 'glibc_2.7' not found (required by $HOME/usr/lib/libffi.so)
linux-gate.so.1 (0xffffe000)
libc.so.6 => /lib/i686/libc.so.6 (0xb7e62000)
$HOME/usr/lib/ld-linux.so.2 (0x80000000)

Из сообщения видно, что для libffi.so задействуется штатная версия glibc: /lib/i686/libc.so.6, но ожидается версия не ниже glibc_2.7. Справиться с этой проблемой помогает указание приоритетных путей для поиска библиотек системой сборки:

$ ./configure --prefix=$PREFIX LDFLAGS='-L/lib -L/usr/lib'

Суммируя сказанное, если собираемому пакету не требуется новая версия библиотеки glibc, при конфигурировании исходных текстов перед сборкой можно создать переменную LDFLAGS со значением '-Wl,-rpath,/lib,-L/lib -L/usr/lib'.

Это позволяет обойти многие проблемы, но, к сожалению, не все. Некоторые программы требуют дополнительные библиотеки при старой версии glibc. Сложность конфигурирования инструментов сборки для таких случаев существенно превышает эстетические неудобства от вынесения новой версии glibc в отдельный каталог.

Приложение 2. Использованные пакеты программного обеспечения

Ключевые слова: приложения, операционные системы, динамические библиотеки, компиляторы.