5/5 - (2 голоса)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

./configure —prefix=$SPREFIX; make; make install

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

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

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

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

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

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

тоже останется без изменений. Потребуется обновить лишь GCC и Binutils.

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

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

configure: error: C++ compiler missing or inoperational

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

Для сборки GCC в каталог с исходными текстами нужно распаковать вспомогательные пакеты точной и комплексной арифметики (ISL, GMP, MPFR и МРС) и создать в нем символические ссылки на версионированные папки:

Зачем нужно выделять glibc?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

configure: error: Building GCC requires GMP 4.2+, MPFR 2.4.0+ and МРС 0.8.0+.

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

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

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

Сборка glibc

Основная роль библиотеки glibc — реализация интерфейса между функциями стандарта POSIX и системными вызовами ядра операционной системы. Поэтому она находится в сильной зависимости от ядра.

Если, например, в среде дистрибутива Maridriva 2008 можно без особенных проблем собрать самую современную версию компилятора GCC 82, то к выбору совместимой версии glibc нужно подходить с большой осмотрительностью, ориентируясь на период расцвета ядра версии 2.6. В результате ряда экспериментов была найдена подходящая версия для модернизации — glibc-2.16.0.

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

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

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

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

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

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

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

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

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

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

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

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

Запуск программы с новой версией 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 (с загрузчиком динамических библиотек $НОМЕ/ glibc-2.16/lib/ld-linux.so2 -> Id-2.16.0.so).

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

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

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

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

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

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

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

Сборка GTK+

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

  • zlibl-devel 1.2.3-8mdv2008.0:
  • libpng-devel 1.2.19-2mdv2008.0:
  • Iibfreetype6-devel 2.3.5-2mdv2008.0:
  • libxl 1_6-devel 1.1.3-2mdv2008.0.
  • Iibxrandr2-devel 1.2.2-1 mdv2008.0.

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

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

в соответствии с деревом зависимостей:

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

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

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

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

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

  • Для выполнения динамически компонуемых программ операционная система задействует загрузчик динамических библиотек.
  • Загрузчик динамических библиотек является частью пакета glibc и представляет собой статически скомпонованную программу.
  • Путь к загрузчику на этапе компиляции программы записывается в файл с е-двоичным кодом: Лib/id-iinux.so2.
  • Для запуска программы альтернативным загрузчиком нужно выполнить сам загрузчик, передав ему в качестве параметров имя запускаемой программы и приоритетные пути поиска динамических библиотек.
  • Основные пути поиска динамических библиотек задаются в конфигурационном файле /etc/ld.so.conf, на основе которого с помощью команды:
    строится индексный файл /etc/id.so.cache, используемый загрузчиком.
  • Приоритетные пути поиска динамических библиотек могут быть заданы через переменную окружения PKG_ CONFIG_PATH
  • Приоритетный путь поиска runtime-библиотек, с которыми компилятор связывает код программы, может быть изменен с помощью опции компоновщика -rpath, которая может быть передана через переменную параметров компилятора в виде:
  • Порядок обхода путей системой сборки в поисках динамических библиотек может быть изменен и дополнен посредством указания:

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

Источник: журнал «Системный администратор»