Портежи-1. Устройство системы

Алексей Федорчук
[email protected]

Система портежей (Portage) - то, что придает Gentoo Linux своеобразие, обеспечивает гибкость и легкость его использования. Она создавалась (и это явным образом признается авторами) под воздействием портов FreeBSD. Однако идет значительно дальше, пронизывая весь дистрибутив с самого его основания.

Содержание

Что такое портежи

Если в двух словах, портежи - система автоматизации установки пакетов из исходных текстов. Посредством соответствующих команд она обеспечивает:

  • получение архивов исходных текстов (тарбаллов) устанавливаемой программы из Сети (с мастер-сайтов разработчиков, их официальных зеркал или серверов Gentoo-проекта);
  • проверку для устанавливаемой программы отношений зависимости от других пакетов или использования оных (см. ниже);
  • скачивание пакетов, от которых зависит устанавливаемая программа, или пакетов, которые она использует;
  • проверку контрольных сумм всех скачанных архивов;
  • декомпрессию и развертывание тарбаллов в специально предназначенный для этого временный каталог;
  • конфигурирование исходных текстов для приведения их в соответствие с реалиями данной системы и, если нужно, наложение патчей, необходимых для сборки и работы именно в Gentoo; патчи эти также получаются из Сети - с сервера проекта;
  • компиляцию как собираемой программы, так и всех пакетов, от которых она зависит или которые использует;
  • установку полученных в результате компиляции бинарных файлов в специальный промежуточный каталог;
  • размещение бинарников в соответствующих ветвях текущей файловой системы, что имеет своим следствием получение работоспособной инсталлированной программы;
  • последнее действие может заменяться (или дополняться) сборкой из временно инсталлированных откомпилированных файлов бинарного пакета в формате *.tbz2 (tar-архива, сжатого компрессором bzip2), пригодного для автономной установки (в т.ч. и на другой машине);
  • регистрацию установленной программы (со всеми пакетами, от которых она зависит или которые использует) в специальной базе данных;
  • переустановку и (или) обновление любого установленного пакета;
  • чистое удаление установленных пакетов, в том числе, при желании - вместе с пакетами, от которых те зависят или которые используют.

Терминологическое замечание: в соответствие с оригинальной терминологией, принятой в документации Gentoo-проекта, здесь и далее различаются следующие отношения между пакетами: зависимости и использования. Отношение зависимости - это когда пакет А для своей установки и функционирования жестко требует наличия в системе уже установленного пакета Б. Так, интегрированную среду KDE невозможно установить (и запустить), если предварительно не была установлена библиотека Qt, на которой она основана. Или еще проще: ни одно приложение графического режима не может быть установлено без оконной системы Икс (примеры таких зависимостей можно многократно умножить.

Отношения зависимости контролируются системой портежей автоматически. Так, попытка установить любой оконный менеджер приведет либо к предварительному скачиванию и установки Иксов, либо к сообщению об ошибке. Впрочем, при необходимости контроль зависимостей может быть отключен - если пользователь знает, что делает (и имеет к тому веские причины).

Отношения использования возникают, когда программа А при наличии в системе программы Б может обрести некие дополнительные функции (хотя сама по себе способна функционировать и без этого). Пример - консольные программы типа links или Midnight Commander: при наличии в системе службы консольной мыши gmp в них возможно использование этого устройства как указательно-позиционирующего (подобно принятому в Windows). Хотя и без gpm они вполне способны успешно выполнять свои задачи (на мой взгляд, так более успешно, но это - совсем другая история).

Отношения использования являются, если так можно выразиться, более мягкими, чем отношения зависимости. Для управления ими используется переменная USE, значения которой могут определяться различными способами. Во-первых, некий предопределенный умолчальный набор отношений использования задается глобально при установке системы портежей. Во-вторых, каждый вновь устанавливаемый пакет, который может быть использован другими пакетами для расширения их функциональности, автоматически добавляет в сумму значений переменной USE соответствующие отношения использования. В третьих, отношения использования могут быть явным образом включены или отключены в соответствующем конфигурационном файле. И наконец, в четвертых: переменную USE, как и любую другую, можно определить в командной строке для выполнения текущей команды установки или как переменную окружения для всего сеанса работы.

Таким образом, разделяя отношения зависимости и отношения использования, система портежей сочетает простоту и гибкость использования. То есть она полностью снимает с пользователя заботу о выполнении жестких отношений зависимости, позволяя широко использование (или не-использование) пакетами дополнительных возможностей.

Действительно, пользователь пакетного дистрибутива вынужден в этом отношении целиком полагаться на волю сборщиков соответствующего пакета. Вспомним, как часто установке Midnight Commander из прекомпилированного пакета влечет за собой установку не только Иксов, но и Gtk с GNOME - не потому, что mc жить без них не может, а лишь потому, что так показалось нужным разработчикам дистрибутива. Если же устанавливать в таком дистрибутиве пакеты вручную - потребуется каждый раз указывать в командной строке ./configure опции with/without или enable/disable. Даже в системе портов FreeBSD соответствующие опции отданы на откуп майнтайнеру порта - если требуются нестандартные настройки, процесс портирования приходится разбивать на этапы с ручным конфигурированием.

К слову сказать, это - не единственное отличие портежей Gentoo от портов FreeBSD. В последних предусматривается самостоятельный порт не просто для каждой программы, но и (почти) для каждой ее версии. Так, для примера, для установки текущей версии редактора joe используется одноименный порт, порт же для разрабатываемой версии - самостоятелен, и носит имя joe-devel. В едином же портеже Gentoo мирно уживается несколько версий одного пакета. То есть в каждый момент времени из текущего среза дерева портежей можно установить не только последнюю (или последнюю стабильную) версию данного пакета, но и несколько более ранних (или, напротив, разрабатываемых) версий. Зачем это нужно - думаю, пояснений не требуется: далеко не всегда новая версия, какие бы фронтирные фичи она ни поддерживала, будет столь же стабильна, как проверенная временем.

И, чтобы более к этому вопросу не возвращаться, главное отличие портежей Gentoo от портов FreeBSD: если первые предназначены для установки дополнительных пакетов (то есть выходящих за пределы базовой системы, т.н. Distributions), то весь дистрибутив Gentoo построен на системе портежей. И базовые компоненты Gentoo (включая исходные тексты ядра, компилятор gcc, библиотеку glibc, да и саму систему портежей) устанавливаются, регистрируются, пересобираются и обновляются точно по тому же механизму, что и любые опциональные приложения.

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

Дерево портежей

Дерево портежей размещается в каталоге /usr/portage. Он содержит множество подкаталогов - app-admin, app-arch, и т.д. Назначение большинства, как правило, понятно из названия: они объединяют группы пакетов по назначению. Группы эти именуются категориями. В каждой из категорий - подкаталоги более глубокого уровня вложенности, отвечающие уже отдельным пакетам. Так, в каталоге app-editors обнаруживаются каталоги для редакторов emacs, vim, joe и т.д., в каталоге app-shells - подкаталоги для оболочек zsh, tcsh и прочих.

Каталог каждого пакета содержит в обязательном порядке подкаталог files, файл ChangeLog и один или несколько файлов вида имя_пакета-номер_версии.ebuild - как уже говорилось, в составе единого портежа может сосуществовать (и обычно сосуществует) несколько версий портированного пакета.

Ясно, что ebuild-файл представляет собой главный компонент портежа - тот самый сценарий, по которому осуществляется установка пакета. Он содержит:

  • краткое описание программы (поле DESCRIPTION);
  • URL домашней страницы проекта;
  • один или несколько адресов для получения исходников пакета;
  • ключевые слова, указывающие на архитектуры, для которых пакет реализован;
  • тип лицензии, под которой пакет распространяется разработчиком (например, GPL-2 или BSD);
  • список пакетов, связанных с данным отношениями зависимости или использования.

Отношения зависимости описываются следующим образом:

DEPEND=">=категория/пакет-версия"

где символ >= показывает, что для установки данного пакета требуется пакет имя_рек версии, равной или более поздней, чем указано. Отношения использования описываются несколько иначе:

DEPEND="keyword? ( >=категория/пакет-версия )"

где ключевое слово (keyword) совпадает с соответствующим флагом переменной USE, а в скобках указывается пакет (вместе с его категорией), который отвечает за реализацию этого флага.

Заметим, что поле DEPEND описывает пакеты, необходимые (или желательные) для компиляции данной программы. В ebuild-файлах некоторых пакетов можно увидеть также и поле RDEPEND - в нем приведены пакеты, необходимые для запуска программы (т.н. runtime-зависимости). Формат его аналогичен таковому поля DEPEND. Если поле RDEPEND не определено, это значит, что runtime-зависимости совпадают с отношениями зависимости и использования, устанавливаемыми для компиляции пакета.

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

  • функция src_unpack отвечает за распаковку архива исходников,
  • функция src_compile - за начальное конфигурирование и компиляцию исходных текстов,
  • функция src_install - за помещение скомпилированных файлов во временный инсталляционный каталог,

и так далее. С форматом ebuild-файла, полным списком его переменных, функций и их описанием можно ознакомиться на странице

$ man 5 ebuild

В подкаталоге files содержатся т.н. дайджест-файлы, которые имеют вид digest-имя_пакета-номер_версии. В каждом таком файле (очевидно, что число их совпадает с количеством ebuild-файлов в родительском каталоге) приведены имя и размер архива исходников для конкретной версии данного пакета, а также - контрольная сумма MD5: именно посредством сверки с дайджест-файлом осуществляется верификация скачанного архива перед его распаковкой.

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

Кроме подкаталогов, соответствующих категориям пакетов, в дереве портежей /usr/portage имеется также несколько подкаталогов специального назначения. К ним относятся:

  • distfiles, в который помещаются скачанные из Сети архивы исходников портированных пакетов;
  • eclass, содержащий т.н. eclass-файлы, описывающие общие условия сборки серии родственных пакетов;
  • licenses, в котором собраны тексты всех лицензий (числом более полутора сотен), на условиях которых распространяются портированные программы их авторами;
  • metadata, файлы которого содержат сведения, аналогичные вводной части ebuild-файла (описание зависимостей, URL мастер-сайта и источника архива, краткое описание, и т.д.);
  • profiles, содержащий т.н. профильные файлы системы портежей, о которых речь пойдет в одном из следующих разделов;
  • scripts, содержащий сценарии для автоматизации некоторых действий по установке портежей (например, скрипт bootstrap.sh, обеспечивающий пересборку базовых компонентов системы, и еще несколько).

Кроме всего прочего, в дереве портежей может обнаружиться и каталог packages. Он предназначен для размещения автономных бинарных пакетов и создается автоматически при сборке первого из них. А внутри него - подкаталог All, куда, собственно, и помещается собранный бинарный пакет (вида *.tbz2), и подкаталоги для отдельных категорий. В последних содержатся символические ссылки на файлы пакетов из подкаталога All.

И еще: в каталоге /usr/portage содержатся два скелетных файла, призванных облегчить построение портежей - skel.ebuild и skel.ChangeLog. Нетрудно догадаться, что по образу и подобию первого создается ebuild-файл портируемого пакета, а второго - файл изменений.

Программы для работы с портежами

Для работы с деревом портежей предназначены две основные программы - /usr/bin/emerge и /usr/sbin/ebuild. Обе они выполняют описанный в первом разделе комплекс действий по управлению портированными пакетами, однако реализуются эти действия по разному.

Программа emerge определяется как высокоуровневый интерфейс командной строки для управления портежами. Это сценарий на языке Python, интерпретатор которого запускается модификатором окружения (/usr/bin/env). Устройство его довольно сложное, но доступное для просмотра (в текстовом редакторе или командой less).

Программа emerge - универсальна, предоставляя доступ ко всем возможностям системы портежей, от определения зависимостей единичного пакета до его окончательной инсталляции в системе или сборки автономного бинарника. Это достигается с помощью указания многочисленных опций (options), действий (actions) и путей (ways) программы, о которых речь впереди (и которые описаны на странице man 1 emerge). Пока же отмечу только, что программа merge не требует указания на конкретный ebuild-файл. Данная в форме

$ emerge /usr/portage/категория/пакет

она автоматически выберет последнюю (или последнюю стабильную) версию указанного пакета, автоматически определит для него все отношения зависимости и использования, скачает и установит недостающие пакеты, если таковые потребуются, после чего скомпилирует и установит собственно заказанную программу.

Программа ebuild (скрипт на языке Python, интерпретируемый последним непосредственно) определяется как низкоуровневый интерфейс к системе портежей. Она, напротив, предназначена для работы с единичным ebuild-файлом, отвечающим конкретной версии данного пакета, каковой и требуется ей в качестве аргумента. Она также способна выполнить как установку пакета, так и сборку автономного бинарника. Определяются ею и отношения зависимости и отношения использования. Однако, в отличие от emerge, ebuild не разрешает нарушения зависимостей автоматически, а просто выдает список недостающих в системе компонентов (естественно, с прекращением своей работы). Это, казалось бы, делает ее менее универсальной. Однако она более гибка в управлении и потому, как будет показано ниже, в ряде случаев использование программы ebuild оказывается более удобным. Кроме того, по сравнению с программой emerge, ebuild предоставляет дополнительную возможность - сборку бинарных пакетов в формате rpm, которые могут быть установлены в дистрибутиве Red Hat и его клонах.

Программа ebuild будет подробно рассмотрена в одном из следующих разделов. Пока же отметим, что весьма подробные сведения о ней можно почерпнуть со станицы man (1) ebuild, которую не следует путать со станицей man (5) ebuild, описывающей устройство ebuild-скрипта.

Кроме универсальных программ управления портежами, в эту систему входит еще несколько специализированных утилит, имеющих местонахождением каталог /usr/lib/portage/bin (впрочем, и программы emerge и ebuild физически находятся здесь - указанные выше пути ведут к символическим на них ссылкам). Они весьма многочисленны, плохо документированы (man-страниц для них, как правило, нет, в лучшем случае информацию можно почерпнуть, запустив такую утилиту с опцией --help, да и то не всегда). Главное же - у меня пока ни разу не возникла необходимость обращаться к ним. И потому далее о этих утилитах речи не будет. Хотя за любую информацию по сему предмету буду признателен.

База данных портежей

База данных установленных пакетов, создаваемая системой портежей, расположена в каталоге /var/db/pkg. Он устроен по образу и подобию каталога /usr/portage, включая серию подкаталогов, соответствующих категориям пакетов - app-editors, app-shells и т.д. Однако внутри каждой категории можно обнаружить только подкаталоги, содержащие ранее установленные пакеты и одноименные их ebuild-файлам, например, /var/db/pkg/app-editors/joe-2.9.8_pre1 и так далее.

В каждом таком каталоге обнаруживается ebuild-файл, идентичный таковому из каталога /usr/portage, и серия файлов с информацией о пакете:

  • CATEGORY, где приведена категория, к которой отнесен пакет (например, для примера с редактором joe это будет app-editors);
  • CHOST, CFLAGS и CXXFLAGS, указывающие наименование целевой машины, флаги для компиляторов C и C++, соответственно;
  • USE, в котором перечислены значения одноименной переменной, при которых пакет был скомпилирован;
  • LICENSE, указывающий тип лицензии, на условиях которой пакет распространяется;
  • CONTENTS, содержащий список всех файлов пакета, инкорпорированных в текущую файловую систему, и каталогов, куда они были помещены, и COUNTER, в котором приведено общее количество этих файлов;
  • RDEPEND, описывающий отношения зависимости и отношения использования, необходимые для запуска установленного пакета (runtime-зависимости).

Кроме этого, к системе портежей имеет отношение еще несколько подкаталогов каталога /var. Так, важным представляется каталог /var/tmp/portage/ - в него помещаются для временного хранения промежуточные продукты жизнедеятельности системы портежей, используемые как для инкорпорации скомпилированного пакета в текущую файловую систему, так и для построения автономного бинарного пакета, пригодного для самостоятельной установки вне системы портежей. По завершении портирования этот каталог автоматически очищается (по умолчанию, это положение можно изменить), и в нем сохраняются только log-файлы, документирующие выполненный процесс.

И, наконец, в каталоге /var/cache/edb/dep, разбитом на подкаталоги по категориям пакетов, также фиксируется информация об отношениях зависимости и отношениях использования пакетов.