\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 <ldv@altlinux.ru> \\ 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 <options>:] добавить указанные параметры в стандартный набор \%opflags;
	\item[\%remove\_optflags <options>:] убрать указанные параметры из стандартного набора \%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}
