\documentclass[russian,notitlepage,a4paper]{article} \usepackage[koi8-r]{inputenc} \usepackage{babel} \textwidth=18cm \oddsidemargin=-1.04cm %\headheight=0cm %\textheight=28cm %\headsep=0cm %\topmargin=-1.54cm \author{Dmitry~V.~Levin \\ ALT Linux Team} \title{Packaging HOWTO \\ (revision 0.3)} \begin{document} \maketitle \section{Введение} При разработке изменений и дополнений к {\it rpm} решались следующие задачи: \begin{description} \item[Обеспечить желаемую функциональность:] наши пакеты должны отвечать определенным правилам, о которых пойдет речь несколько позже. Для этого надо, чтобы {\it spec}-файлы обеспечивали выполнение этих правил. \item[Помочь разработчику:] так как {\it spec}-файлы все еще пишут люди, то их работу нужно свести к тому минимуму, который, собственно, и требует участия человека. Разработчик не должен копировать блоки кода из файла в файл, ибо эта неинтеллектуальная работа отнимает массу сил и чревата ошибками. Для этого есть макросы. Если какой-то код появляется в разных {\it spec}-файлах более одного раза, то надо написать макрос(ы). \item[Сделать {\it spec}-файлы более читабельными:] те, кто эти файлы читает - тоже живые люди. Им будет удобнее, если в наименовании, расположении и использовании различных элементов {\it spec}-файлов будет определенный порядок. \end{description} \section{Особенности этой версии rpm.} \subsection{Новые макросы.} \subsubsection{Макросы для часто используемых каталогов.} \begin{description} \item[X11R6:] \%\_x11dir, \%\_x11bindir, \%\_x11libdir, \%\_x11includedir, \%\_x11mandir, \%\_x11datadir; \item[лицензии:] \%\_licensedir; \item[меню:] \%\_menudir, \%\_iconsdir, \%\_miconsdir, \%\_liconsdir; \item[emacs:] \%\_emacslispdir; \item[другие системные:] \%\_initdir, \%\_lockdir, \%\_logdir. \end{description} \subsubsection{Управление опциями компилятора {\it gcc}.} \begin{description} \item[\%add\_optflags :] добавить указанные параметры в стандартный набор \%opflags; \item[\%remove\_optflags :] убрать указанные параметры из стандартного набора \%opflags; \item[\%optflags\_core:] базовые параметры; \item[\%\_optlevel:] уровень оптимизации; \item[\%optflags\_optimization:] параметры, отвечающие за оптимизацию, кроме архитектурно-зависимых; \item[\%optflags\_warnings:] warning options; \item[\%optflags\_debug:] debugging options; \item[\%optflags\_shared:] параметры, применяемые для создания relocatable файлов; \item[\%optflags\_nocpp:] параметры, отключающие поддержку C++ exceptions и C++ RTTI; \item[\%optflags\_notraceback:] -fomit-frame-pointer; \item[\%optflags\_fastmath:] -ffast-math; \item[\%optflags\_strict:] -fstrict-aliasing; \item[\%optflags\_kernel:] параметры, используемые при компиляции ядра и его модулей. \end{description} По умолчанию, стандартный набор \%opflags состоит из "\%optflags\_core \%optflags\_warnings \%optflags\_optimization". \subsubsection{Макросы-надстройки над утилитой {\it make}.} \begin{description} \item[\%make\_build:] вызов make с параметром, обеспечивающим оптимальную параллельную сборку в данной среде; \item[\%make\_install:] вызов make c инициализацией переменной {\it INSTALL}, что в случае корректной реализации {\it Makefile}ов пакета позволяет сохранить дату последней модификации файлов, что особенно важно для документации; \item[\%makeinstall:] ``{\it \%make\_install} <инициализация других переменных, используемых многими {\it Makefile}ами> {\it install}''. \end{description} \subsubsection{Регистрация документации в формате {\it info}.} \begin{description} \item[\%install\_info:] регистрация новых/обновленных {\it info}-страниц; \item[\%uninstall\_info:] отмена регистрации удаленных {\it info}-страниц. \end{description} \subsubsection{Регистрация меню.} \begin{description} \item[\%update\_menus:] регистрация новых/обновленных меню; \item[\%clean\_menus:] отмена регистрации удаленных меню. \end{description} \subsubsection{Вспомогательные макросы \%configure.} \begin{description} \item[\%\_\_libtoolize:] путь к скрипту {\it libtoolize}; \item[\%\_configure\_script:] путь к скрипту {\it configure}; \item[\%\_configure\_target:] целевая платформа для {\it configure}; \item[\%\_configure\_gettext:] --without-included-gettext. \end{description} \subsubsection{Серверные макросы.} \begin{description} \item[\%post\_service:] регистрация нового сервиса при установке, перезапуск при обновлении; \item[\%preun\_service:] отмена регистрации сервиса и его выключение при удалении. \end{description} \subsubsection{Макросы, определяющие некоторые аспекты packaging policy.} \begin{description} \item[\%buildroot:] значение {\it BuildRoot}; \item[\%\_defattr:] атрибуты файлов и каталогов по умолчанию для каждой секции {\it \%files} и для каждого файла, включаемого в этих секциях; \item[\%\_compress\_method:] метод, используемый при сжатии документации в секции {\it \%install}; \item[\%\_strip\_method:] метод, используемый при обработке {\it ELF}-файлов в секции {\it \%install}; \item[\%\_findreq\_default\_method:] метод, используемый по умолчанию при поиске требуемых зависимостей; \item[\%\_findprov\_default\_method:] метод, используемый по умолчанию при поиске предоставляемых зависимостей; \item[\%set\_strip\_method:] изменить значение макроса {\it \%\_strip\_method}; \end{description} \subsubsection{Вызов вспомогательных программ.} \begin{description} \item[\%find\_lang:] вызов {\it /usr/lib/rpm/find-lang} \item[\%strip\_executable:] вызов {\it /usr/lib/rpm/brp-strip} для обработки {\it ELF executables}; \item[\%strip\_relocatable:] вызов {\it /usr/lib/rpm/brp-strip} для обработки {\it ELF relocatables}; \item[\%strip\_shared:] вызов {\it /usr/lib/rpm/brp-strip} для обработки {\it ELF shared objects}; \item[\%strip\_static:] вызов {\it /usr/lib/rpm/brp-strip} для обработки {\it ELF ar archives}; \item[\%cleanup\_build:] вызов {\it /usr/lib/rpm/brp-cleanup}; \item[\%compress\_docs:] вызов {\it /usr/lib/rpm/brp-compress}; \item[\%strip\_binaries:] вызов {\it /usr/lib/rpm/brp-strip}; \item[\%clean\_buildroot:] выполнение {\it rm -rf \%buildroot}, если {\it \%buildroot} не указывает на настоящий /. \end{description} \subsubsection{Управление процессом сборки.} \begin{description} \item[\%buildmulti:] Альтернативная директива {\it \%build} для случая, когда в секции {\it \%build} происходит заполнение {\it \%buildroot}. Вообще говоря, такой техники стоит избегать во всех случаях, когда это возможно. \end{description} \subsubsection{Версии некоторых установленных в системе пакетов.} \begin{description} \item[glibc:] {\it \%\_\_glibc\_version}, {\it \%\_\_glibc\_version\_major}, {\it \%\_\_glibc\_version\_minor}; \item[python:] {\it \%\_\_python\_version}; \item[\%get\_version:] Версия указанного пакета; \item[\%get\_release:] Релиз указанного пакета; \item[\%get\_serial:] Serial указанного пакета; \item[\%add\_serial:] Serial указанного пакета в виде, пригодном для включения в {\it spec}-файл. \end{description} Эти макросы, как правило, используются в пакетах, сборка которых возможна с различными версиями этих программ, если эти версии правильно учитывать. \subsubsection{Прочие макросы.} \begin{description} \item[\%intel:] список архитектур {\it intel}, совместимых с {\it i386}; \item[\%amd:] список архитектур {\it amd}, совместимых с {\it i386}; \item[\%ix86:] список всех архитектур, совместимых с {\it i386}; \item[компоненты макроса \%packager:] {\it \%packagerName}, {\it \%packagerAddress}. \end{description} \subsection{Новыe параметры rpm.} \begin{description} \item[-bE:] новый режим работы {\it rpm}, при котором происходит только подстановка макросов; \item[--nowait-lock:] не блокировать процесс, если база данных {\it rpm} занята; \item[--fancypercent:] отображать дополнительную информацию о процентах проделанной работы при установке/обновлении пакетов. \end{description} \subsection{Новые возможности rpm.} \subsubsection{Автоматический поиск требуемых и предоставляемых зависимостей.} В дополнение к стандартному поиску зависимостей от/для разделяемых библиотек, реализована поддержка поиска требуемых зависимостей для {\it shell} и {\it perl}-скриптов, а также поддержка поиска предоставляемых зависимостей для {\it perl}-скриптов. \subsubsection{Изменение семантики тэгов, управляющих поиском зависимостей.} Новые возможности {\it rpm} по автоматическому поиску зависимостей при сборке пакетов управляются, как и прежде, значениями тэгов {\it AutoReq}, {\it AutoProv} и {\it AutoReqProv}. К стандартным значениям {\it yes}/{\it no} ({\it true}/{\it false}), таким образом, добавлены новые возможные значения, являющиеся именами методов поиска зависимостей: \begin{itemize} \item {\it lib}: включение поиска зависимостей от/для разделяемых библиотек; \item {\it shell}: включение поиска зависимостей в {\it shell}-скриптах; \item {\it perl}: включение поиска зависимостей в {\it perl}-скриптах; \item {\it nolib}: выключение поиска зависимостей от/для разделяемых библиотек; \item {\it noshell}: выключение поиска зависимостей в {\it shell}-скриптах; \item {\it noperl}: выключение поиска зависимостей в {\it perl}-скриптах; \item {\it default}: то же, что и {\it yes}; \item {\it none},{\it off}: то же, что и {\it no}; \item {\it all}: включение всех возможных методов поиска зависимостей. \end{itemize} Значением тэга может являться как один метод, так и перечисление методов. По умолчанию, для каждого под пакета собираемого пакета {\it AutoReq} = {\it AutoProv} = {\it yes}, что на практике означает использование макросов {\it \%\_findreq\_default\_method} и {\it \%\_findprov\_default\_method} для определения методов поиска зависимостей. \subsubsection{Автоматическое сжатие {\it man} и {\it info}-документации с поддержкой различных методов сжатия.} Вся документация пакета, распознаваемая как {\it man} или {\it info}-документация, по окончании работы секции {\it \%install}, сжимается согласно выбранному методу. Поддерживаются следующие методы сжатия: \begin{itemize} \item {\it bzip2}: сжатие с помощью ``{\it bzip2 -9}''; \item {\it gzip}: сжатие с помощью ``{\it gzip -9n}''; \item {\it auto}: сжатие с помощью ``{\it gzip -9n}'' либо ``{\it bzip2 -9}'' в зависимости от того, какой вариант окажется эффективнее; \item {\it none}: производится декомпрессия файлов вместо сжатия; \item {\it skip}: процедура сжатия пропускается полностью. \end{itemize} Какой метод будет использован в каждом конкретном случае, зависит от значения макроса {\it \%\_compress\_method}; значение по умолчанию для этого макроса - {\it auto}. По окончании процедуры сжатия производится выравнивание ссылок, которые, возможно, требуют коррекции в связи с изменениями имен файлов в процессе их сжатия. \subsubsection{Автоматическое удаление отладочной информации из {\it ELF}-файлов с поддержкой различных стратегий выбора файлов, подлежащих обработке.} Зачастую возможно уменьшить размер получаемых в результате сборки пакета {\it ELF}-файлов без потери качества за счет удаления из них отладочной информации. Поэтому по окончании работы секции {\it \%install} все {\it ELF}-файлы выбранных типов обрабатываются программой {\it strip}. Выбор типов файлов определяется значением макроса {\it \%\_strip\_method}, которое есть набор из следующих возможных значений: \begin{itemize} \item {\it executable}: ELF executable; \item {\it relocatable}: ELF relocatable; \item {\it shared}: ELF shared object; \item {\it static}: ar archive. \end{itemize} Кроме того, есть возможность вызывать {\it strip} вручную, для этой цели предназначены макросы {\it \%strip\_executable}, {\it \%strip\_relocatable}, {\it \%strip\_shared}, {\it \%strip\_static}. Синтаксис этих макросов подробно изложен в ``{\it /usr/lib/rpm/brp-strip --help}''. \subsubsection{Автоматическая перекомпиляция python-модулей.} Как известно, {\it python}-модули обычно компилируют в байтовую форму для увеличения быстродействия при последующей работе с ними. Каждый такой модуль, помимо всего прочего, хранит время своего создания и полное имя файла, в котором должен находиться. В связи с последним обстоятельством скомпилированные модули, созданные в результате работы секции {\it \%install}, непригодны, ибо не могут быть использованы после установки пакета. По этой причине теперь по окончании работы секции {\it \%install} производится перекомпиляция всех {\it python}-модулей таким образом, чтобы их можно было использовать после установки пакета. В качестве байт-компилятора будет использоваться программа, имя которой хранится в макросе {\it \%\_\_python}. Обычно это {\it /usr/bin/python}, однако в некоторых случаях может потребоваться изменить это значение на другое (например, в случае сборки пакета {\it python} или если по какой-то причине перекомпиляция не нужна). \subsubsection{BuildRoot.} Времена, когда тэг {\it BuildRoot} в {\it spec}-файле определял, какой каталог {\it rpm} будет использовать в качестве {\it BuildRoot}, прошли безвозвратно. Теперь этот таг не несет никакой информации и может (и должен) быть опущен. Вместо этого используется значение макроса {\it \%buildroot}, который определен как ``\%\{\_tmppath\}/\%\{name\}-buildroot'' в файле {\it /usr/lib/rpm/macros} и может быть переопределен в любом месте, где допускается определять макросы. В случае, если макрос {\it \%buildroot} не определен либо его значение представляет собой недопустимое значение ``/'', сборка пакета не будет выполнена. \subsubsection{Автоматическая очистка BuildRoot.} Перед выполнением секции {\it \%install} и по окончании выполнения секции {\it \%clean} {\it rpm} автоматически очищает {\it BuildRoot} с помощью макроса {\it \%clean\_buildroot}. Это значит, что больше не нужно использовать эти ужасные ``rm -rf \$RPM\_BUILD\_ROOT''. Секция {\it \%clean} вообще может (и должна) быть опущена, если в ней не содержится ничего, кроме этого ``rm''. В тех редких случаях, когда в {\it spec}-файле производится заполнение {\it BuildRoot} не в секции {\it \%install}, как это должно быть, а в секции {\it \%build}, что в принципе неправильно, можно перенести точку очистки {\it BuildRoot} из начала секции {\it \%install} в начало секции {\it \%build}, если заменить директиву {\it \%build} на макрос {\it \%buildmulti}. \subsubsection{Упрощение секции \%files.} Ранее в начале каждой секции {\it \%files} было необходимо указывать атрибуты файлов и каталогов создаваемых пакетов с помощью довольно однообразно используемой директивы {\it \%defattr}. Теперь это происходит автоматически в начале каждой секции {\it \%files}, а также в начале каждого файла, включаемого в секцию {\it \%files} с помощью опции {\it -f}. Точнее говоря, в качестве этой директивы используется значение макроса {\it \%\_defattr}. Таким образом, прежнее использование директивы {\it \%defattr} в начале секций и файлов следует считать упраздненным. \subsubsection{Сборка пакетов привилегированным пользователем.} То, что когда-то было необходимостью, со временем стало излишним, а порой и просто опасным. Теперь, когда все пакеты, кроме одного-единственного {\it MAKEDEV}, можно (и нужно) собирать непривилегированным пользователем во избежание риска разрушения системы и некорректной сборки, сборка пакетов привилегированным пользователем по умолчанию запрещена. Этот запрет можно снять путем изменения значения макроса {\it \%\_allow\_root\_build}. \section{Пожелания packager'у.} \subsection{Устаревшие конструкции.} Не следует использовать устаревшие конструкции - они лишь загромождают {\it spec}-файл, снижая тем самым его читабельность. К устаревшим конструкциям, в частности, относятся: \begin{itemize} \item тэг {\it BuildRoot:}; \item cтроки вида {\it rm -rf \$RPM\_BUILD\_ROOT}; \item {\it \%\_defattr} со стандартными аргументами в начале файлов и секций {\it \%files}; \item секция {\it \%clean}, пустая либо без разумного содержания. \end{itemize} \subsection{Фигурные скобки.} Нет смысла засорять текст {\it spec}-файла ненужными фигурными скобками. Избавится от них легко: \begin{verbatim} perl -pi -e 's/%\{([A-Za-z_0-9]+)\}([^A-Za-z_0-9?*]|$)/%$1$2/g' spec-файл \end{verbatim} \subsection{Порядок тэгов.} Рекомендуемый порядок заголовочных тэгов: {\it Name}, {\it Version}, {\it Release}, {\it Serial}, далее {\it Summary}, {\it License}, {\it Group}, {\it Url}, {\it Packager}, {\it BuildArch}, потом {\it Source}, {\it Patch}, далее {\it Provides}, {\it Requires}, {\it PreReqs}, {\it Conflicts}, и, наконец, {\it Prefix}, {\it BuildPreReqs}, {\it BuildRequires}. Разумеется, не все из вышеперечисленных тэгов, как правило, используются, равно как встречаются и другие редко используемые тэги. В связи с тем, что {\it BuildRequires} зарезервирован для автоматически вычисляемых зависимостей, для указания особых зависимостей следует использовать {\it BuildPreReq}. \subsection{Файлы локализации.} Если в состав пакета входят файлы локализации либо другие файлы на разных языках, стоит использовать макрос {\it \%find\_lang}. Подробная информация есть в ``/usr/lib/rpm/find-lang -h'' \subsection{Группы.} Следите за значением тэгов {\it Group}: они должны соответствовать действительности и при этом принадлежать фиксированному множеству, перечисленному в файле {\it /usr/lib/rpm/GROUPS}. \subsection{Внутрипакетные зависимости.} При работе с мультипакетными {\it spec}-файлами соблюдайте правило внутрипакетных зависимостей: Если один пакет в какой-либо мере зависит от другого подпакета, то эта зависимость должна быть указана полностью, включая не только имя, но также верcию, релиз и serial (если есть). Например, ``Requires: \%name = \%version-\%release''. Обратите внимание на синтаксис: знак равенства, в отличие от дефиса, окружен пробелами. \subsection{Разделяемые библиотеки.} Пакеты, содержащие как разделяемые библиотеки, так и использующие их программы, должны быть разделены на подпакеты таким образом, чтобы в подпакет, содержащий разделяемые библиотеки, не входили использующие их программы. Это позволит уменьшить количество циклических зависимостей. По традиции, имена пакетов, состоящих только из разделяемых библиотек, должны начинаться с префикса ``lib`` либо содержать его внутри слова. При разделении подпакетов следует помнить о внутрипакетных зависимостях. \subsection{Статические библиотеки.} Статические библиотеки должны паковаться в отдельные подпакеты, что связано со спецификой их использования. Если имя devel-подпакета заканчивается суффиксом {\it -devel}, то имя нового devel-static-подпакета будет заканчиваться суффиксом {\it -devel-static}. При разделении подпакетов следует помнить о внутрипакетных зависимостях: В списке зависимостей devel-static-подпакета должна присутствовать зависимость от {\it -devel = \%version-\%release}. \subsection{Переименование пакетов.} Иногда пакеты переименовывают. Например, это случается при упаковке разделяемых библиотек. В таких случаях следует указывать правильную информацию о зависимостях, необходимую для корректного обновления. В частности, дожен присутствовать: \begin{itemize} \item тэг {\it Provides: старое\_имя = \%version} \item тэг {\it Obsoletes: старое\_имя} \end{itemize} \begin{thebibliography}{9} \bibitem{wwwrpm} Официальный web-сайт rpm: http://www.rpm.org/ \bibitem{mailrpm} Список рассылки для разработчиков rpm: rpm-list@redhat.com \bibitem{maxrpm} Edward C. Bailey ``Maximum RPM'' February 17, 1997. (доступна также online-версия по адресу http://www.rpmdp.org/rpmbook/ и в формате PostScript по адресу http://www.rpm.org/maximum-rpm.ps.gz) \end{thebibliography} \end{document}