\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@logic.ru> \\ IPLabs Linux Team}
\title{Packaging howto \\ (preliminary revision 0.1)}

\begin{document}
\maketitle

\section{Введение}

При разработке изменений и дополнений к $rpm$ решались следующие задачи:
\begin{description}
	\item[Обеспечить желаемую функциональность:] наши пакеты должны отвечать
	определенным правилам, о которых пойдет речь несколько позже. Для этого
	надо, чтобы $spec$-файлы обеспечивали выполнение этих правил.
	\item[Помочь разработчику:] так как $spec$-файлы все еще пишут
	люди, то их работу нужно свести к тому минимуму, который, собственно, и
	требует участия человека. Разработчик не должен копировать блоки кода
	из файла в файл, ибо эта неинтеллектуальная работа отнимает массу сил и
	чревата ошибками. Для этого есть макросы. Если какой-то код появляется в
	разных $spec$-файлах более одного раза, то надо написать макрос(ы).
	\item[Сделать $spec$-файлы более читабельными:] те, кто эти файлы читает -
	тоже живые люди. Им будет удобнее, если в наименовании, расположении и
	использовании различных элементов $spec$-файлов будет определенный порядок.
\end{description}

\section{Особенности этой версии rpm.}

\subsection{Новые макросы.}

\subsubsection{Макросы для часто используемых каталогов.}
\begin{description}
	\item[X11R6:] \%\_x11dir;
	\item[initscripts:] \%\_initdir;
	\item[лицензии:] \%\_licensedir;
	\item[меню:] \%\_menudir, \%\_iconsdir, \%\_miconsdir, \%\_liconsdir.
\end{description}

\subsubsection{Управление опциями компилятора $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\_debug \%optflags\_warnings \%optflags\_optimization".

\subsubsection{Макросы-надстройки над утилитой $make$.}
\begin{description}
	\item[\%make\_build:] вызов make с параметром, обеспечивающим оптимальную параллельную сборку в данной среде;
	\item[\%make\_install:] вызов make c инициализацией переменной $INSTALL$,
		что в случае корректной реализации $Makefile$ов пакета позволяет сохранить
		дату последней модификации файлов, что особенно важно для документации;
	\item[\%makeinstall:] ``$\%make\_install$ <инициализация других переменных,
		используемых многими $Makefile$ами> $install$''.
\end{description}

\subsubsection{Регистрация документации в формате $info$.}
\begin{description}
	\item[\%install\_info:] регистрация новых/обновленных $info$-страниц;
	\item[\%uninstall\_info:] отмена регистрации удаленных $info$-страниц.
\end{description}

\subsubsection{Регистрация меню.}
\begin{description}
	\item[\%update\_menus:] регистрация новых/обновленных меню;
	\item[\%clean\_menus:] отмена регистрации удаленных меню.
\end{description}

\subsubsection{Вспомогательные макросы \%configure.}
\begin{description}
	\item[\%\_configure\_script:] путь к скрипту $configure$;
	\item[\%\_configure\_target:] целевая платформа для $configure$;
	\item[\%\_configure\_gettext:] --without-included-gettext.
\end{description}

\subsubsection{Макросы, определяющие некоторые аспекты packaging policy.}
\begin{description}
	\item[\%buildroot:] значение $BuildRoot$;
	\item[\%\_defattr:] атрибуты файлов и каталогов по умолчанию для каждой секции $\%files$ и для каждого файла, включаемого в этих секциях;
	\item[\%\_compress\_method:] метод, используемый при сжатии документации в секции $\%install$;
	\item[\%\_strip\_method:] метод, используемый при обработке $ELF$-файлов в секции $\%install$;
	\item[\%\_findreq\_default\_method:] метод, используемый по умолчанию при поиске требуемых зависимостей;
	\item[\%\_findprov\_default\_method:] метод, используемый по умолчанию при поиске предоставляемых зависимостей;
	\item[\%set\_strip\_method:] изменить значение макроса $\%\_strip\_method$;
\end{description}

\subsubsection{Вызов вспомогательных программ.}
\begin{description}
	\item[\%find\_lang:] вызов $/usr/lib/rpm/find-lang$
	\item[\%strip\_executable:] вызов $/usr/lib/rpm/brp-strip$ для обработки $ELF executables$;
	\item[\%strip\_relocatable:] вызов $/usr/lib/rpm/brp-strip$ для обработки $ELF relocatables$;
	\item[\%strip\_shared:] вызов $/usr/lib/rpm/brp-strip$ для обработки $ELF shared objects$;
	\item[\%strip\_static:] вызов $/usr/lib/rpm/brp-strip$ для обработки $ELF ar archives$;
	\item[\%cleanup\_build:] вызов $/usr/lib/rpm/brp-cleanup$;
	\item[\%compress\_docs:] вызов $/usr/lib/rpm/brp-compress$;
	\item[\%strip\_binaries:] вызов $/usr/lib/rpm/brp-strip$;
	\item[\%clean\_buildroot:] выполнение $rm -rf \%buildroot$, если $\%buildroot$ не указывает на настоящий /.
\end{description}

\subsubsection{Управление процессом сборки.}
\begin{description}
	\item[\%buildmulti:] Альтернативная директива $\%build$ для случая,
		когда в секции $\%build$ происходит заполнение $\%buildroot$.
		Вообще говоря, такой техники стоит избегать во всех случаях, когда
		это возможно.
\end{description}

\subsubsection{Версии некоторых установленных в системе пакетов.}
\begin{description}
	\item[glibc:] $\%\_\_glibc\_version$, $\%\_\_glibc\_version\_major$, $\%\_\_glibc\_version\_minor$;
	\item[python:] $\%\_\_python\_version$.
\end{description}
Эти макросы, как правило, используются в пакетах, сборка которых возможна
с различными версиями этих пакетов, если эти версии правильно учитывать.

\subsubsection{Прочие макросы.}
\begin{description}
	\item[\%intel:] список архитектур $intel$, совместимых с $i386$;
	\item[\%amd:] список архитектур $amd$, совместимых с $i386$;
	\item[\%ix86:] список всех архитектур, совместимых с $i386$;
	\item[компоненты макроса \%packager:] $\%packagerName$, $\%packagerAddress$.
\end{description}

\subsection{Новыe параметры rpm.}
\begin{description}
	\item[-bE:] новый режим работы $rpm$, при котором происходит только подстановка макросов;
	\item[--nowait-lock:] не блокировать процесс, если база данных $rpm$ занята;
	\item[--fancypercent:] отображать дополнительную информацию
		о процентах проделанной работы при установке/обновлении пакетов.
\end{description}

\subsection{Новые возможности rpm.}

\subsubsection{Автоматический поиск требуемых и предоставляемых зависимостей.}
В дополнение к стандартному поиску зависимостей от/для разделяемых библиотек,
реализована поддержка поиска требуемых зависимостей для $shell$ и $perl$-скриптов,
а также поддержка поиска предоставляемых зависимостей для $perl$-скриптов.

\subsubsection{Изменение семантики тэгов, управляющих поиском зависимостей.}
Новые возможности $rpm$ по автоматическому поиску зависимостей при сборке пакетов
управляются, как и прежде, значениями тэгов $AutoReq$, $AutoProv$ и $AutoReqProv$.
К стандартным значениям $yes$/$no$ ($true$/$false$), таким образом, добавлены новые
возможные значения, являющиеся именами методов поиска зависимостей:
\begin{itemize}
	\item $lib$: включение поиска зависимостей от/для разделяемых библиотек;
	\item $shell$: включение поиска зависимостей в $shell$-скриптах;
	\item $perl$: включение поиска зависимостей в $perl$-скриптах;
	\item $nolib$: выключение поиска зависимостей от/для разделяемых библиотек;
	\item $noshell$: выключение поиска зависимостей в $shell$-скриптах;
	\item $noperl$: выключение поиска зависимостей в $perl$-скриптах;
	\item $default$: то же, что и $yes$;
	\item $none$,$off$: то же, что и $no$;
	\item $all$: включение всех возможных методов поиска зависимостей.
\end{itemize}
Значением тэга может являться как один метод, так и перечисление методов.
По умолчанию, для каждого подпакета собираемого пакета $AutoReq$ = $AutoProv$ = $yes$,
что на практике означает использование макросов $\%\_findreq\_default\_method$ и
$\%\_findprov\_default\_method$ для определения методов поиска зависимостей.

\subsubsection{Автоматическое сжатие $man$ и $info$-документации с поддержкой различных
методов сжатия.}
Вся документация пакета, распознаваемая как $man$ или $info$-документация, по окончании
работы секции $\%install$, сжимается согласно выбранному методу.
Поддерживаются следующие методы сжатия:
\begin{itemize}
	\item $bzip2$: сжатие с помощью ``$bzip2 -9$'';
	\item $gzip$: сжатие с помощью ``$gzip -9n$'';
	\item $auto$: сжатие с помощью ``$gzip -9n$'' либо ``$bzip2 -9$'' в зависимости от того,
		какой вариант окажется эффективнее;
	\item $none$: производится декомпрессия файлов вместо сжатия;
	\item $skip$: процедура сжатия пропускается полностью.
\end{itemize}
Какой метод будет использован в каждом конкретном случае, зависит от значения макроса
$\%\_compress\_method$; значение по умолчанию для этого макроса - $auto$.
По окончании процедуры сжатия производится выравнивание ссылок, которые, возможно,
требуют коррекции в связи с изменениями имен файлов в процессе их сжатия.

\subsubsection{Автоматическое удаление отладочной информации из $ELF$-файлов
с поддержкой различных стратегий выбора файлов, подлежащих обработке.}
Зачастую возможно уменьшить размер получаемых в результате сборки пакета
$ELF$-файлов без потери качества за счет удаления из них отладочной информации.
Поэтому по окончании работы секции $\%install$ все $ELF$-файлы выбранных типов
обрабатываются программой $strip$. Выбор типов файлов определяется значением макроса
$\%\_strip\_method$, которое есть набор из следующих возможных значений:
\begin{itemize}
	\item $executable$: ELF executable;
	\item $relocatable$: ELF relocatable;
	\item $shared$: ELF shared object;
	\item $static$: ar archive.
\end{itemize}
Кроме того, есть возможность вызывать $strip$ вручную, для этой цели предназначены
макросы $\%strip\_executable$, $\%strip\_relocatable$, $\%strip\_shared$, $\%strip\_static$.
Синтаксис этих макросов подробно изложен в ``$/usr/lib/rpm/brp-strip --help$''.

\subsubsection{Автоматическая перекомпиляция python-модулей.}
Как известно, $python$-модули обычно компилируют в байтовую форму для увеличения
быстродействия при последующей работе с ними. Каждый такой модуль, помимо всего прочего,
хранит время своего создания и полное имя файла, в котором должен находиться. В связи с
последним обстоятельством скомпилированные модули, созданные в результате работы секции
$\%install$, непригодны, ибо не могут быть использованы после установки пакета.
По этой причине теперь по окончании работы секции $\%install$ производится перекомпиляция
всех $python$-модулей таким образом, чтобы их можно было использовать после установки пакета.
В качестве байт-компилятора будет использоваться программа, имя которой хранится в макросе
$\%\_\_python$. Обычно это $/usr/bin/python$, однако в некоторых случаях может потребоваться
изменить это значение на другое (например, в случае сборки пакета $python$ или если по какой-то
причине перекомпиляция не нужна).

\subsubsection{BuildRoot.}
Времена, когда тэг $BuildRoot$ в $spec$-файле определял, какой каталог $rpm$ будет
использовать в качестве $BuildRoot$, прошли безвозвратно. Теперь этот таг не несет
никакой информации и может (и должен) быть опущен. Вместо этого используется значение макроса
$\%buildroot$, который определен как ``\%\{\_tmppath\}/\%\{name\}-buildroot'' в файле
$/usr/lib/rpm/macros$ и может быть переопределен в любом месте, где допускается определять
макросы. В случае, если макрос $\%buildroot$ не определен либо его значение представляет собой
недопустимое значение ``/"", сборка пакета не будет выполнена.

\subsubsection{Автоматическая очистка BuildRoot.}
Перед выполнением секции $\%install$ и по окончании выполнения секции $\%clean$ $rpm$
автоматически очищает $BuildRoot$ с помощью макроса $\%clean\_buildroot$. Это значит, что
больше не нужно использовать эти ужасные ``rm -rf \$RPM\_BUILD\_ROOT''. Секция $\%clean$
вообще может (и должна) быть опущена, если в ней не содержится ничего, кроме этого ``rm''.
В тех редких случаях, когда в $spec$-файле производится заполнение $BuildRoot$ не в секции
$\%install$, как это должно быть, а в секции $\%build$, что в принципе неправильно, можно
перенести точку очистки $BuildRoot$ из начала секции $\%install$ в начало секции $\%build$,
если заменить директиву $\%build$ на макрос $\%buildmulti$.

\subsubsection{Упрощение секции \%files.}
Ранее в начале каждой секции $\%files$ было необходимо указывать атрибуты файлов и
каталогов создаваемых пакетов с помощью довольно однообразно используемой
директивы $\%defattr$. Теперь это происходит автоматически в начале каждой секции $\%files$,
а также в начале каждого файла, включаемого в секцию $\%files$ с помощью опции $-f$.
Точнее говоря, в качестве этой директивы используется значение макроса $\%\_defattr$.
Таким образом, прежнее использование директивы $\%defattr$ в начале секций и файлов
следует считать упраздненным.

\subsubsection{Сборка пакетов привилегированным пользователем.}
То, что когда-то было необходимостью, со временем стало излишним, а порой и просто опасным.
Теперь, когда все пакеты, кроме одного-единственного $MAKEDEV$, можно (и нужно) собирать
непривилегированным пользователем во избежание риска разрушения системы и некорректной
сборки, сборка пакетов привилегированным пользователем по умолчанию запрещена. Этот запрет
можно снять путем изменения значения макроса $\%\_allow\_root\_build$.

\section{Пожелания packager'у.}
\begin{enumerate}
	\item Не следует использовать устаревшие конструкции - они лишь загромождают $spec$-файл,
		снижая тем самым его читабельность. К устаревшим конструкциям, в частности, относятся:
		``BuildRoot: ...'', ``rm -rf \$RPM\_BUILD\_ROOT'', $\%\_defattr$ со стандартными
		аргументами в начале файлов и секций $\%files$, секция $\%clean$ без разумного содержания.
	\item Нет смысла засорять текст $spec$-файла ненужными фигурными скобками.
		Избавится от них легко: \

		``perl -pi -e `$s/\%\backslash\{([A-Za-z\_0-9]+)\backslash\}([\neg A-Za-z\_0-9]|\$)/\%\$1\$2/g$' $spec$-файл''.
	\item Рекомендуемый порядок заголовочных тэгов: $Name$, $Version$, $Release$, $Serial$,
		далее $Summary$, $License$, $Group$, $Url$, $Packager$, потом $Source$, $Patch$,
		далее $Provides$, $Requires$, $PreReqs$, $Conflicts$, и, наконец,
		$Prefix$, $BuildPreReqs$, $BuildRequires$. Разумеется не все из вышеперечисленных
		тэгов, как правило, используются, равно как встречаются и другие редко используемые
		тэги. В связи с тем, что $BuildRequires$ зарезервирован для автоматически
		вычисляемых зависимостей, для указания особых зависимостей следует использовать $BuildPreReqs$.
	\item Если в состав пакета входят файлы локализации либо другие файлы на разных языках,
		стоит использовать макрос $\%find_lang$. Подробная информация есть в
		``/usr/lib/rpm/find-lang -h''
\end{enumerate}

Продолжение следует...

\end{document}
