Несколько лет назад, когда Linux использовали на инфраструктурных
серверах и компьютерах энтузиастов, было "модно" собирать ПО из
исходных текстов. Плох тот линуксоид, который не может пройти книжку
LFS и собрать свой дистрибутив.
Подобный путь, хотя поначалу и интересен, влечет за собой массу
трудностей, когда речь заходит о поддержке сколько-нибудь масштабной
инфраструктуры. Сборка ПО из исходных текстов чревата потерями
времени, машинно-специфичными сборками, потерей стандартизации, а
следовательно и контроля над ПО. Прямым следствием этого с технической
точки зрения является возрастание расходов рабочего времени на
управление ПО, а с экономической - удорожание обслуживания
инфраструктуры.
Решение подобной проблемы - использование специального ПО и политики
управления пакетами с целью стандартизации управления жизненным циклом
ПО. Одним из решений для управления ПО является использование формата
RPM, а также одноименного менеджера пакетов.
RPM - что это такое?
Что такое пакет? Прежде всего пакет - это единица управление ПО. Пакет
состоит из:
1. Файлов, исполняемых и конфигурационных
2. Предустановочных действий.
3. Постустановочных действий
4. Действий, необходимых для удаления ПО.
5. Различной служебной информации (списки и контрольные суммы файлов
и т.д.)
Соответственно, пакет - это несколько больше, чем просто архив файлов.
RPM-пакеты - основной способ управления ПО во многих дистрибутивах
Linux. Разумно использовать его и для управления собственным ПО / ПО
третьих лиц, которое не распространяется в виде RPM по умолчанию.
Именно этим мы и займемся. Примеры из данной статьи разобраны и
протестированы на RHEL5, хотя по аналогии будут работать и во многих
других дистрибутивах.
Подготовка окружения для сборки RPM
В любой системе существует стандартная инфраструктура для сборки RPM.
По умолчанию она расположена в /usr/src/redhat/. Если подобного
каталога нет, установите пакет rpm-build. Его наличие позволяет
собирать пакеты, имея административные привилегии, что не всегда
безопасно. Мы будем использовать сборку под непривилегированным
пользователем, которого назовем brewbuilder.
Для демонстрации нам потребуется пакет hello-1.0.tar.gz, который можно
взять с сервера
ftp://62.205.185.52/765591143807cc23efcfb4f1b436ebbc/hello-1.0.tar.gz
Для того, чтобы сделать пользовательско-специфичное окружение для
сборки RPM, нам нужно всего лишь создать директории и переопределить
один макрос.
Теперь мы готовы к сборке. Для сборки нам необходим единственный файл
hello-1.0.tar.gz, который надо разместить в
~/workspace/redhat/SOURCES.
Часть основная - содержательная. SPEC-файл.
SPEC-файл - центральная часть процесса сборки. Написание корректного
SPEC-файла и является целью нашей сегодняшней работы. Итак приступим.
Есть простой способ обеспечить себе шаблон для сборки - запустите
emacs. =) Сложный - сделайте себе шаблон в вашем любимом редакторе
(читай VIM) или запомните необходимые стадии. Мы приведем сразу весь
SPEC-файл, позже разобрав его построчно. (Нумерация строк приведена
только для удобства, в реальном SPEC-файле нумерация не нужна.)
Итак, начнем. В строчках [1-6] находится стандартное описание пакета.
Эти поля необходимы, но назначение их чисто описательное за
исключением поля Source0, в котором указано имя архива с исходными
текстами. Помимо поля Source0, могут быть и Source1, Patch0 и далее по
аналогии.
Строчки [11-13] (секция %description) задают описание пакета. Это
стандартное многострочное описание, выводимое командой rpm -qi.
Строки [16-17] (секция %prep) отвечаю за подготовку пакета к сборке.
Единственная строчка в нашем случае - макрос %setup отвечает за
"тихую" (флаг -q) распаковку исходников Source0 в каталог
%{name}-%{version}. В этой секции полагается размещать подготовку
исходников с сборке, применение патчей и т.п.
Строки [19-20] (секция %build) отвечают за сборку исходников. В нашем
случае это делается просто командой make. В общем случае это почти
всегда комманды ./configure -prefix=$RPM_BUILD_ROOT/usr; make.
Секция %install [22-28] отвечает за установку файлов в окружении
сборки. В нашем случае стандартной цели make install нет, поэтому мы
устанавливаем все вручную. В общем случае make install в этой секции
почти всегда решит ваши проблемы. Заметьте, что все пути начинаются с
$RPM_BUILD_ROOT. Это достаточно важно и это главная причина не
собирать пакеты под пользователем root. В случае если вы - root и вы
забудете $RPM_BUILD_ROOT в начале пути, то вместо установки в
"песочнице" ваш файл будет установлен на вашей рабочей системе, чего
вы вряд ли хотите. =)
Секция %files [30-34] - одна из наиболее важных частей нашего
SPEC-файла. Она описывает файлы, входящие в RPM-пакет. В этой секции
желательно определить макросом %defattr(-,root,root) атрибуты по
умолчанию (владелец - root, группа root, доп. атрибутов нет.), иначе
при установке RPM-пакета пользователь увидит жалобы на то, что
пользователь brewbuilder не существует. При создании списка файлов
можно использовать шаблоны с символами '*' и '?', но делать это
следует осмотрительно, так как указание списка файлов как /* приведет
к включению лишних файлов в пакет. Специально можно пометить
конфигурационные файлы (%config), что приведет к специальному
обращению с ними, например при обновлении пакета, документацию (%doc)
и пустые директории, принадлежащие пакету (%dir). Подробнее об
использовании этих и других опций вы сможете прочитать в отдельных
статьях.
Секция %clean [36-38] описывает очистку временного окружения сборки и
обычно ничего кроме двух указанных команд не содержит.
Секция %post [40-42] описывает постинсталляционный скрипт. В нашем
случае мы добавляем /usr/local/lib к пути, по которым доступны
разделяемые библиотеки и успокаиваемся на этом. При написании данной
секции мы сделали очевидную ошибку. Ошибка заключается в том, что мы
не выдержали транзакционность. При удалении пакета мы не можем просто
убрать строчку /usr/local/lib из файла /etc/ld.so.conf, потому что мы
не можем рассчитывать, что никто другой не проверял наличие там этой
строчки. С другой стороны, если мы - последний пакет, которому эта
строчка нужна - неплохо было бы все таки иметь возможность удалить ее
- для чистоты процесса. Для этого придумали директории, вроде
/etc/ld.so.conf.d/. Чтобы добавить путь к библиотекам корректно, нам
просто необходимо создать свой файл со строчкой /usr/local/lib в этой
директории, а при удалении пакета (например, в неописанной в данной
статье секции %preun) удалить этот файл.
И последняя секция %changelog содержит историю пакета. История пишется
записями с фиксированным форматом даты, имени и адреса электронной
почты. Формат дальнейших заметок произволен. Рекомендуется серьезно
отнестись к changelog'ам, дабы избежать проблем в будущем.
Сборка пакета
Сборка пакета осуществляется одной командой
rpmbuild -ba [путь к SPEC-файлу]
После чего вы можете исследовать директории %_topdir/RPMS и
%_topdir/SRPMS, найти там собранные пакеты и исследовать их командами
rpm -q ...., установить и удалить соответственно.
Заключение
Вот мы и собрали наш первый RPM-пакет. Если вы хотите узнать более
тонкие моменты сборки RPM, то рекомендуем прочесть книгу RPM Guide,
доступную по адресу http://docs.fedoraproject.org/drafts/rpm-guide-en/ .
В дальнейшем мы обязательно расскажем о подписи RPM-пакетов и создании
собственных репозитариев для yum.