Сборка RPM - быстрый старт
Содержание
Подготовка к сборке и обзор spec-файла
Сперва давайте разберёмся, что должно быть в системе для сборки rpm-пакета. Обязательно должен быть установлен пакет rpm-build. Без него не будет доступна команда rpmbuild. Наряду с ним, по зависимостям поставится еще ряд пакетов, используемых при сборке. В зависимостях для сборки пакета в РОСЕ обычно не принято прописывать компилятор C/C++, по этому поводу рано или поздно вам понадобятся пакеты gcc и gcc-c++ Все остальные зависимости должен попросить сам пакет. Конечно бывают промахи, и в процессе сборки вы понимаете, что что-то упустили, но это обычно бывает довольно редко и не критично.
А что собственно из себя представляет RPM пакет? RPM-пакеты делятся на пакеты с исходниками - src.rpm и пакеты, готовые к установке - %{arch}.rpm. В src.rpm пакетах содержится исходный тарболл (исходник программы), какие-либо другие исходники, пачти и самый главный spec-файл, который управляет процессом сборки. Все эти файлы упакованы в cpio архив. Когда вы пытаетесь войти в src.rpm пакет при помощи файлового менеджера mc, вы его увидите. Также в пакете присутствует некоторые файлы с информацией.
В %{arch}.rpm-пакетах содержится cpio-архив с файлами, которые после установки разложатся по соответствующим каталогам, файлы информации и установочные скрипты.
Также вы можете встретить без исходного кода. Обычно их создают для проприетарных программ, которые нельзя включать в дистрибутив (исходников нет, а бинарник каким-то образом нужно переделать либо просто запрещено размещать на зеркалах дистрибутива лицензией). Внутри этого пакета находится обычно только spec-файл, а бинарник скачивается и, при необходимости, модифицируется, в процессе установки пакета (например, в post-скрипте, о котором речь пойдет ниже).
Собирать пакеты можно из-под любого пользователя. Делать это из-под root'а не рекомендуется, т.к. есть вероятность, что корнем для секции инсталляции окажется каталог / и тогда команда rm -rf %{buildroot} уничтожит все на свете. Также бывает, что «кривые» пакеты не правильно выполняют инсталляцию, и ставятся не во временный каталог, а прямо куда-нибудь в %{_prefix} (/usr). Часть файлов будет потеряна, хотя на работоспособности пакета на этой машине понятное дело это не скажется.
Что нужно сделать, чтобы можно было собирать пакеты из-под обычного пользователя? Первым делом нужно создать в своём домашнем каталоге файл директорию rpmbuild со следующей структурой:
~/rpmbuild |-- BUILD |-- BUILDROOT |-- RPMS | |-- i586 | |-- x86_64 | `-- noarch |-- SOURCES |-- SPECS `-- SRPMS
Каталоги BUILD, RPMS, SOURCES, SPECS, SRPMS вам необходимо создать вручную, подкаталоги каталога RPMS должны создаться автоматически во время сборки в зависимости от архитектуры.
В РОСЕ не принято писать сборщика пакета и вендора в spec-файлах; эти значения выставляются автоматически системой сборки ABF. Также ABF автоматически подписывает собранные пакеты ключом соответствующего репозитория. Поэтому эти вопросы мы здесь затрагивать не будем.
Теперь давайте посмотрим что из себя представляет самый главный файл rpm-пакета, spec-файл. Для примера возьмём его из пакета stardict. Этот пакет хорошо подходит для обучения, так как в нем есть несколько тарболов (исходник программы, упакованный tar’ом), получается несколько пакетов и есть такая вещь, как схемы. Обычно spec-файл имеет такое же имя, как и сам пакет (stardict.spec). Однако вы можете добавить версию пакета (stardict-2.spec), удобно если вы пытаетесь поддерживать несколько веток программ. Можно даже дать какое-нибудь другое название, однако это мягко говоря не удобно.
Итак, содержимое файла stardict.spec приведено ниже. Мы сразу будем вставлять комментарии после определенных секций, но если вы соедините все блоки в один и тот же файл, то получите полноценный stardict.spec.
Spec-файл состоит из секций и шапки:
Summary: StarDict dictionary Name: stardict Version: 2.4.8 Release: 4 License: GPL URL: http://stardict.sourceforge.net Group: User Interface/Desktops Source0: %{name}-%{version}.tar.bz2 Source1: %{name}-tools-%{version}.tar.bz2 Patch0: %{name}-2.4.8-desktop.patch
Summary — краткое описание пакета, Name — название, Version — версия, Release — релиз. Последним трем тегам соответствуют макроопределения %{name} , %{version} , %{release} . Их часто используют в дальнейшем. Name и Version обычно совпадает с название тарбола. Если же они отличаются, то в принципе ничего страшного, но придётся в некоторых местах spec-файла действовать нестандартными методами. Если вы собираете пакет из cvs, svn и т. д., то рекомендуется в самом начале файла сделать макроопределение %define date 20070422 (именно в таком формате, сами догадайтесь почему) и тег Release определить следующим образом:
Release: 0.git%{date}.4
Далее, License — лицензия, под которой распространяется программа (обычно указано в самом пакете). Раньше в ходу был также тег Copyright, но сейчас он не используется. URL — сайт программы, Group — группа, в которую будет входить данный пакет. Обычно следует прикинуть на что этот пакет похож, и посмотреть группу похожего пакета. Придумывать группу самому не стоит, лучше посмотреть в список имеющихся.
Source* — исходные тексты, тарболы, просто файлы. В данном примере идут два тарбола с разными программами, что делает сборку намного сложнее. Обычные файлы, например, конфигурации, могут просто копироваться в секции %%install при помощи команды install. У нее простой синтаксис, install -m маска_как_у_chmod что куда. При помощи нее можно также создавать каталоги. В нашем примере она не используется, но подробнее про неё можно почитать в man.
Patch — патчи, исправления, которые вы или кто-то другой выпустили для данного пакета. Не принято изменять исходный текст самой программы, а затем завертывать ее в тарбол. Принято накладывать заплатки. Делать их можно следующим образом. Распаковываете исходный тарбол, у нас это будет stardict-2.4.8, далее копируете stardict-2.4.8 в stardict-2.4.8.orig. После этого изменяете код в каталоге stardict-2.4.8, выходите из него и отдаете команду diff -ur stardict-2.4.8.orig stardict-2.4.8 > stardict-2.4.8-название_патча.patch. Как видно, до навания патча идёт %{name}-%{version} пакета. В самом spec-файле обязательно следует писать название патча без макроопределений. По крайней мере версию, точно. Иначе при обновлении версии пакета, у вас и обновится версия патча, определённая макросом %{version} , а патч может быть подойдёт к новой версии программы и без каких либо изменений. Если же во время самой сборки патч не смог наложиться, то его следует либо переделать под данную версию программы, либо отключить в секции %setup .
В spec-файлах пакетов многих дистрибутивов вы также можете в заголовке встретить определение BuildRoot - каталога, в котором осуществляется сборка. В РОСЕ в этом определении нет необходимости, имя BuildRoot формируется автоматически.
BuildRequires: libgnomeui-devel >= 2.2.0 BuildRequires: scrollkeeper BuildRequires: gettext
Requires(post): GConf2 Requires(post): scrollkeeper Requires(postun): scrollkeeper
BuildRequires — секция, в которую через запятую или через пробел прописываются пакеты, которые требуются для сборки нашей программы. Почерпнуть их можно из каких-нибудь файлов README и INSTALL (хотя там редко бывает что-то полезное по этому поводу), из процесса конфигурации (на данный момент обычно это скрипт configure) и из самого процесса сборки (иногда configure что-нибудь пропустит и сборка остановится).
Requires — в эту секцию записываются пакеты или файлы(!), которые будет требовать данный пакет при установке. При сборке в зависимости автоматически пропишутся все библиотеки, которые наш пакет потребует, но вы также можете указать пакеты вручную. Rpm также автоматически прописывает зависимости perl, python, mono и некоторые другие (все эти зависимости прописываются не в spec-файл разумеется, а в сам пакет). Если вам не нужно, чтобы зависимости прописывались автоматически, следует прописать в spec-файл новый тег AutoReq: no. Обычно его прописывают при сборки проприетарных программ, так как rpm добавляет внутренние зависимости из собираемой программы.
В нашем примере используются конструкции Requires(post) и Requires(postun) для зависимостей в скриптах установки и удаления. В принципе достаточно и простого Requires. Здесь особенно нечего комментировать. Просто самому StarDict в процессе работы эти зависимости не нужны. Нужны они только при инсталляции и удалении.
Есть ещё несколько полезных тегов, которые здесь не используются.
Provides: название1, название2
- другие названия, помимо %{name} , на которые будет откликаться данный пакет. Удобно указывать, если вы сменили название пакета, а другие пакеты продолжают зависеть от старого названия.
Obsoletes: название1, название2
— удаление указанных пакетов при установки текущего пакета. Как бы говорится, что данный пакет замещает собой указанные (по функциональности, по набору файлов и т. п.). Можно использовать конструкцию название <. Тут вы должны сами понимать, что к чему.
Conflicts: название1, название2
— перечисляются пакеты, которые конфликтуют с текущим. Подразумевается что указанные пакеты нужно вручную удалить, перед установкой нашего. Также используются конструкции со знаками сравнения и версиями (см. выше).
Suggests: название1, название2
- мягкие зависимости - пакеты, которые добавляют данному пакету дополнительную функциональность (например, кодеки для медиапроигрывателя), но без которых можно обойтись.
Epoch: число
— обычно или не указывается совсем или равняется 0. Суть этого параметра вот в чем. Пусть всё наш же пакет stardict имеет версию 2.4.8, а также есть более старый 2.4.5. Так вот если %{epoch} у stardict 2.4.5 будет 1, а у 2.4.8 - 0, то пакет 2.4.5 будет всегда новее, чем 2.4.8. О чём при установки вам RPM и скажет. Этот параметр удобен, если вы хотите откатиться на предыдущую версию (разумеется, если вы это все выкладываете в публичный репозиторий и хватаете все через urpmi или rpmdrake. Для «домашних» нужд подойдёт параметр к rpm --force). Если определён тег Epoch: 0, то пакет будет иметь приоритет перед пакетом с непоределённым тегом Epoch.
BuildArch: архитектура
— архитектура, под которую будет собираться наш пакет. Если эта опция не указана, то пакет соберётся под текущую архитектуру. Обычно эту опцию указывают для того, чтобы собирать пакет архитектуры noarch, то есть пакет, в котором нет бинарников.
ExclusiveArch: архитектура1 архитектура2
— архитектуры, под которые данный пакет может быть собран. Обычно используется при сборки модулей к ядру.
На этом шапка заканчивается и начинаются отдельные секции.
%description StarDict is an international dictionary written for the GNOME environment. It has powerful features such as "Glob-style pattern matching," "Scan seletion word," "Fuzzy search," etc.
Описание главного пакета, того, у которого будет имя %{name}
%package tools Summary: StarDict-Editor Requires: %{name} = %{version}-%{release} Group: User Interface/Desktops
Здесь мы создаём новый пакет, название которого будет %{name}-tools. Если нужно обозвать пакет совсем по другому, то следует сделать, например, так: %package -n tools-stardict. Версия нового пакета берётся из заданного тега Version. Обратите внимание на Requires. В нём прописана зависимость на главный пакет stardict. Если бы он имел %{epoch} , то необходимо было бы обязательно указать Requires: %{name}-%{epoch}:%{version}-%{release} . Иначе вам просто не удастся установить это пакет.
%description tools A simple tool for StarDict.
Описание второго пакета
%prep %setup -q -a1 %patch0 -p1
Секция %prep в ней начинается подготовка к сборке. %setup распаковывает исходники. Опция -q не показывает вывод распаковывания архива. Опция -a1 используется для распаковки %{SOURCE1} , второго тарбола внутрь(!) каталога первого тарбола. Соответственно цифра указывает на номер SOURCE. Ещё иногда используется параметр -b, тогда второй тарбол распаковывается в тот же каталог, что и первый. Соответственно если у нас один тарбол, то опции -a, -b не используются.
Если у вас первый каталог в тарболе имеет отличное от %{name}-%{version} название, то rpm не сможет войти автоматом в этот каталог. В таком случае следует немного изменить %setup. Если в архиве stardict-2.4.8.tar.bz2 первый каталог имеет название, например, просто stardict, то выглядеть это будет так:
%setup -q -n %{name} -a1
Сразу после распаковки пакета, перед %patch, если нужно, можно скопировать файлы, или запустить какие либо программы для изменения исходников. Допустим скопировать файл русификации, или подправить sed’ом какой-нибудь исходник. Просто вызываете здесь cp, sed или ещё что-то. В качестве корня здесь выступает каталог, в который распаковался первый тарболл (за него отвечает переменная $RPM_BUILD_DIR, но она крайне редко используется).
При помощи %patch накладываются патчи. Если вы делали патч, как мы писали выше, то у вас всегда будет параметр -p1. Также часто используют параметр -b .название_патча, для создания резервной копии.
%build pushd %{name}-tools-%{version} %configure %make popd
%configure %make
Секция %build, именно здесь происходит сборка пакета. Обратите внимание на pushd и popd. Этими командами мы переходим и выходим из каталога второго тарбола. Именно он будет корневым каталогом после pushd. После команды popd мы вернёмся в каталог первого тарбола. Соответственно если у вас один исходник, то не нужно использовать эти команды.
Так как у нас две программы в одном пакете, то мы выполняем два раза концигурацию %configure и два раза make. Если пакет конфигурируется при помощи autotools, то макросом %configure запускается скрипт configure из корня распакованного тарбола. У него обычно бывает много параметров, их можно посмотреть из командной строки при помощи ./configure --help. После %configure вы можете указать нужные вам параметры. Заметьте, что вызов %configure и ./configure отличаются. В первом случае конфигуратору будут переданы правильные каталоги для инсталляции (а также стандартные параметры), во втором - каталоги по умолчанию.
После успешной конфигурации идет сборка, а именно макрос %make, вызывающий одноименную команду с некоторыми дополнтельными параметрами (в частности, на многопроцессорных машинах используется параллельная сборка - опиця -j).
Если пакет не использует autotools, то %configure, а может и %make использовтаь не нужно, для сборки прочтите файл README и INSTALL. В РОСЕ есть макросы и на другие случаи жизни - например, %cmake для одноименного инструмента сборки.
Когда сборка успешна закончена, в действие вступает секция %install.
%install pushd %{name}-tools-%{version} %makeinstall_std popd
%makeinstall_std
%find_lang %{name}
%%find_lang, поиск файлов локализации. Параметром у неё является название файлов, которые будут лежать после установки в каталоге %{buildroot}/usr/share/locale/*/LC_MESSAGES/*.mo. Обычно оно соответствует %{name} . Если это не так, пишите другое имя.
Во многих spec-файлах вы можете заметить выполнение команды rm -rf %{buildroot} или rm -rf $RPM_BUILD_ROOT в самом начале секции %install, а также секцию %clean с такими же строками. В современной РОСЕ в этом нет необходимости, такая зачистка выполняется автоматически.
%preun %preun_uninstall_gconf_schemas %{name}
Секции для установочных скриптов. Вообще их бывает несколько. %pre — выполняется перед установкой, %post — после установки, %preun — перед удалением, %postun — после удаления. В нашем примере при удалении удаляются схемы Gconf. Здесь мы предполагаем, что в пакете только одна схема и ее имя совпадает с именем пакета. Обратите внимание, что для удаления схем мы вызываем специальный макрос; этот макрос раскрывается rpmbuild РОСЫ в набор необходимых команд оболочки Shell, которые, собственно, и удаляют схему. Установка схем при установке пакета выполняется автоматически за счет файловых триггеров RPM.
Для каждого пакета могут быть свои скрипты, поэтому следует также почитать документацию. Если никаких скриптов для правильной работы не нужно, то и секции эти не следует использовать. В этих секциях можно применять bash-скрипты (впрочем как и в любых других секциях).
В секциях %files мы должны указать какие файлы должны быть упакованы в пакеты. Все файлы должны быть оговорены, в противном случае rpmbuild выдаст сообщение о неупакованных файлах.
Опцией -f указываются файл, содержащий список обрабатываемых файлов. В нашем случае этот файл содержит пути к файлам локализации. Вы в принципе можете создать свой файл и подсунуть его.
Для определения каталогов используются специальные макроопределения.
- %{_prefix} — /usr
- %{_sysconfdir} — /etc
- %{_bindir} — /usr/bin
- %{_datadir} — /usr/share
- %{_libdir} — /usr/lib или /usr/lib64 в зависимости от разрядности системы
- %{_lib} — соответственно /lib или /lib64
- %{_libexecdir} — /usr/libexec
- %{_includedir} — /usr/unclude
- %{_mandir} — /usr/share/man
- %{_sbindir} — /usr/sbin
- %{_localstatedir} — /var.
- %{systemd_libdir} — /usr/lib/systemd
%files -f %{name}.lang %defattr(-, root, root) %doc AUTHORS COPYING INSTALL README NEWS %{_sysconfdir}/gconf/schemas/stardict.schemas %{_bindir}/stardict %{_bindir}/stardict-editor %{_libdir}/bonobo/servers/GNOME_Stardict.server %{_datadir}/applications/*.desktop %{_datadir}/stardict %{_datadir}/locale/*/LC_MESSAGES/* %{_datadir}/pixmaps/stardict.png %{_datadir}/gnome/help/%{name}/* %{_datadir}/idl/GNOME_Stardict.idl %{_datadir}/omf/* %doc %{_mandir}/man?/*
%doc помечает файлы как документацию. Третья строка копирует указанные файлы в каталог %{_datadir}/doc/%{name}-%{version} . По умолчанию файлы в rpm пакете будут иметь владельцем root’а, а права доступа у низ будут такие же, как и в процессе установки. Если это необходимо поменять, то воспользуйтсь конструкцией %defattr.
Далее просто перечисляются файлы.
%files tools %{_bindir}/stardict-editor
Тоже самое для пакета stardict-tools. Если бы он назывался tools-stardict, то %files выглядел бы так:
%files -n tools-%{name}.
Последнее, что идёт в spec-файле, это %changelog. В changelog’е вы указывает изменения в пакете по сравнению с предыдущей версией. Синтаксис его примерно следующий.
%changelog * Sun Apr 22 2007 Your Name <your@email> - 2.4.8-4 - update desktop patch
Макроопределения
Теперь пора познакомиться поближе с макросами и переменными. Допустим, мы собираем пакет из SVN, в данном случае в релиз обычно включается дата ревизии. В самом начале spec-файла нужно определить переменную date:
%define date 20070612
Как мы видим, за определение переменных отвечает макроопределение %define. Теперь в любом месте spec-файла мы можем использовать нашу переменную в виде %{date} (скобки не обязательны, но в РОСЕ принято брать в скобки переменные, и не брать - макроопределения; так их проще различать). Например, определение основных параметров будет выглядеть примерно так:
Version: 0.5 Release: 0.svn%{date}.3
Обратите внимание, что перед датой стоит 0., а после даты - число, которое и увеличивается при необходимости поднять релиз. Зачем так сделано? Когда наконец выйдет окончательная версия (в нашем случае - 0.5), ревизию можно будет убрать, а в релиз прописать просто 1. При этом литерально 1 больше, чем любая строка, начинающаяся на 0, и пакет будет считаться более новым, чем предварительные пакеты, собиравшиеся на основе ревизий SVN.
Крайне популярным макроопределением является конструкция
%if условие действие1 %else действие2 %endif
или просто %if без %else. Суть проста, если условие стоящее при %if истина, то выполняется действие1, в противном случае выполняется действие2.
Допустим, мы опять же собираем что-нибудь из SVN. Обычно внутри архива, если он из SVN, вместо каталога %{name}-%{version} указывают просто %{name} (архив sim-0.9.5.tar.bz2 внутри имеет каталог sim, так как финального релиза sim 0.9.5 не существует. Конечный же релиз будет иметь первым каталогом sim-0.9.5). Чтобы всякий раз не переписывать spec-файл, можно сделать следующие макроопределения:
%define svn 1 ... %prep %if %{svn} %setup -q -n %{name} %else %setup -q %endif
Если переменная svn не определена, то будет выполняться часть сценария после %else. Можно также использовать более строгое условие (не забудьте про кавычки):
%define svn 1 ... %prep %if "%{svn}" == "1" %setup -q -n %{name} %else %setup -q %endif
Внутри всех секций spec-файла мы можем использовать любые команды Linux, без каких либо «наворотов», а вот в шапке файла не всё так просто. Например, нам нужно определить версию firefox для пакета (допустим epiphany) и прописать ее в секцию Requires:. Выглядеть это будет следующим образом:
Requires: firefox = %(rpm -q firefox --qf "%%{version}")
Обратите внимание на то, что внешняя команда выполняется в %() (почти, как в bash - $()) и в spec-файле необходимо ставить два знака % в параметрах. Таким образом можно вызывать любые команды Linux, например, для определения версии ядра.
Ещё одним популярным макроопределение является конструкция %ifarch .. %endif. Если архитектура соответствует указанной после %ifarch, то выполняется какое либо действие. Архитектуры бывают i386, i486, i586, i686, i?86, x86_64, и понятное дело некоторые другие, с которыми вы наверно не столкнётесь.
Как уже отмечалось выше во всех секциях spec-файла вы можете использовать любые команды Shell, включая for, while, if и др.
Сборка пакета
Теперь перейдём непосредственно к сборке пакета. Исходники и патчи должны лежать в каталоге SOURCES, а spec файл в каталог SPECS. После этого нужно отдать команду:
rpmbuild -ba spec-файл
После этого пакет соберётся (или не соберётся, а вывалится с ошибками), и в подкаталогах каталога RPMS появятся бинарные пакеты, а в каталоге SRPMS появится исходник.
Очень часто, перед самым завершением сборки, rpmbuild выдаёт сообщение о найденных, но неупакованных файлах. Это означает, что вы просто не указали их в секции %files. Необходимо просто добавить их туда. Если же вы не хотите чтобы эти файлы попадали в пакет, то можно воспользоваться одним из следующих способов:
- Добавить в секцию %files макроопределение
%exclude путь_к_файлу/файл
- Добавить в начало spec-файла макроопределение
%define _unpackaged_files_terminate_build 0
Если необходимо собрать только бинарник или только исходник, то вместо -ba следует использовать -bb и -bs соответственно. Из полезных параметров rpmbuild можно отметить -clean (удалить весь мусор), -rmsource (удалить исходники из каталога SOURCE) и -target=архитектура (собрать пакет под конкретную архитектуру).
Можно также выполнять сценарии только в определённой секции. Описывать подобные параметры мы здесь не будем, см. man rpmbuild.
Сборка RPM пакета из уже установленного в системе
Иногда случается ситуация, что какой-то пакет уже установлен в системе (может быть в очень старой системе) и очень хочется получить rpm’ку с ним, а она как раз и не сохранилась. Также может захотеться собрать по быстрому пакет с изменёнными под ваши нужды конфигурационными файлами.
Для решения этой проблемы следует воспользоваться утилитой rpmrebuild. Эта написанная на bash утилита доступна в contrib-репозитории РОСЫ.
Работать с ней крайне просто. Нужно отдать всего лишь команду:
rpmrebuild название_установленного_пакета
Если какой-либо файл был изменён, то вам об этом сообщат, но процесс сборки не прервётся.
Rpmrebuild обладает огромным количеством параметров, например, вы можете изменять release пакета, changelog, скрипты, секции Requires, описания пакета и многое другое. Можете даже просто напросто изменить spec-файл, который скрипт сгенерирует сам. Он правда будет немного страшный, но это все же лучше, чем ничего.
Все параметры можно посмотреть при помощи
rpmrebuild --help
и
rpmrebuild --help-plugins
См. также
Эта страница основана на заметках из блога "Записки о Linux":