Сборка RPM — быстрый старт
Этот документ содержит краткий экскурс в сборку RPM-пакетов для систем линейки ROSA Desktop. Документ не претендует на полноту, для более детальной информации смотрите ссылки, приведенные в конце страницы.
Подготовка к сборке и обзор spec-файла
Сперва давайте разберёмся, что должно быть в системе для сборки rpm-пакета. Обязательно должен быть установлен пакет rpm-build . Без него не будет доступна команда rpmbuild. Наряду с ним, по зависимостям поставится еще ряд пакетов, используемых при сборке. В зависимостях для сборки пакета в РОСЕ обычно не принято прописывать компилятор C/C++, по этому поводу рано или поздно вам понадобятся пакеты gcc и gcc-c++ Все остальные зависимости должен попросить сам пакет. Конечно бывают промахи, и в процессе сборки вы понимаете, что что-то упустили, но это обычно бывает довольно редко и не критично.
А что собственно из себя представляет RPM пакет? RPM-пакеты делятся на пакеты с исходниками — src.rpm и пакеты, готовые к установке — %.rpm . В src.rpm пакетах содержится исходный тарболл (исходник программы), какие-либо другие исходники, пачти и самый главный spec-файл, который управляет процессом сборки. Все эти файлы упакованы в cpio архив. Когда вы пытаетесь войти в src.rpm пакет при помощи файлового менеджера mc , вы его увидите. Также в пакете присутствует некоторые файлы с информацией.
В %.rpm-пакетах содержится cpio-архив с файлами, которые после установки разложатся по соответствующим каталогам, файлы информации и установочные скрипты.
Также вы можете встретить без исходного кода. Обычно их создают для проприетарных программ, которые нельзя включать в дистрибутив (исходников нет, а бинарник каким-то образом нужно переделать либо просто запрещено размещать на зеркалах дистрибутива лицензией). Внутри этого пакета находится обычно только spec-файл, а бинарник скачивается и, при необходимости, модифицируется, в процессе установки пакета (например, в post-скрипте, о котором речь пойдет ниже).
Собирать пакеты можно из-под любого пользователя. Делать это из-под root’а не рекомендуется, т.к. есть вероятность, что корнем для секции инсталляции окажется каталог / и тогда команда rm -rf % уничтожит все на свете. Также бывает, что «кривые» пакеты не правильно выполняют инсталляцию, и ставятся не во временный каталог, а прямо куда-нибудь в % ( /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: %-%.tar.bz2 Source1: %-tools-%.tar.bz2 Patch0: %-2.4.8-desktop.patch
Summary — краткое описание пакета, Name — название, Version — версия, Release — релиз. Последним трем тегам соответствуют макроопределения % , % , % . Их часто используют в дальнейшем. Name и Version обычно совпадает с название тарбола. Если же они отличаются, то в принципе ничего страшного, но придётся в некоторых местах spec-файла действовать нестандартными методами. Если вы собираете пакет из cvs, svn и т. д., то рекомендуется в самом начале файла сделать макроопределение %define date 20070422 (именно в таком формате, сами догадайтесь почему) и тег Release определить следующим образом:
Release: 0.git%.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. Как видно, до навания патча идёт %-% пакета. В самом spec-файле обязательно следует писать название патча без макроопределений. По крайней мере версию, точно. Иначе при обновлении версии пакета, у вас и обновится версия патча, определённая макросом % , а патч может быть подойдёт к новой версии программы и без каких либо изменений. Если же во время самой сборки патч не смог наложиться, то его следует либо переделать под данную версию программы, либо отключить в секции %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
— другие названия, помимо % , на которые будет откликаться данный пакет. Удобно указывать, если вы сменили название пакета, а другие пакеты продолжают зависеть от старого названия.
Obsoletes: название1, название2
— удаление указанных пакетов при установки текущего пакета. Как бы говорится, что данный пакет замещает собой указанные (по функциональности, по набору файлов и т. п.). Можно использовать конструкцию название < . Тут вы должны сами понимать, что к чему.
Conflicts: название1, название2
— перечисляются пакеты, которые конфликтуют с текущим. Подразумевается что указанные пакеты нужно вручную удалить, перед установкой нашего. Также используются конструкции со знаками сравнения и версиями (см. выше).
Suggests: название1, название2
— мягкие зависимости — пакеты, которые добавляют данному пакету дополнительную функциональность (например, кодеки для медиапроигрывателя), но без которых можно обойтись.
Epoch: число
— обычно или не указывается совсем или равняется 0. Суть этого параметра вот в чем. Пусть всё наш же пакет stardict имеет версию 2.4.8, а также есть более старый 2.4.5. Так вот если % у 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.
Описание главного пакета, того, у которого будет имя %
%package tools Summary: StarDict-Editor Requires: % = %-% Group: User Interface/Desktops
Здесь мы создаём новый пакет, название которого будет %-tools . Если нужно обозвать пакет совсем по другому, то следует сделать, например, так: %package -n tools-stardict . Версия нового пакета берётся из заданного тега Version . Обратите внимание на Requires . В нём прописана зависимость на главный пакет stardict . Если бы он имел % , то необходимо было бы обязательно указать Requires: %-%:%-% . Иначе вам просто не удастся установить это пакет.
%description tools A simple tool for StarDict.
Описание второго пакета
%prep %setup -q -a1 %patch0 -p1
Секция %prep в ней начинается подготовка к сборке. %setup распаковывает исходники. Опция -q не показывает вывод распаковывания архива. Опция -a1 используется для распаковки % , второго тарбола внутрь(!) каталога первого тарбола. Соответственно цифра указывает на номер SOURCE. Ещё иногда используется параметр -b, тогда второй тарбол распаковывается в тот же каталог, что и первый. Соответственно если у нас один тарбол, то опции -a, -b не используются.
Если у вас первый каталог в тарболе имеет отличное от %-% название, то rpm не сможет войти автоматом в этот каталог. В таком случае следует немного изменить %setup . Если в архиве stardict-2.4.8.tar.bz2 первый каталог имеет название, например, просто stardict , то выглядеть это будет так:
%setup -q -n % -a1
Сразу после распаковки пакета, перед %patch , если нужно, можно скопировать файлы, или запустить какие либо программы для изменения исходников. Допустим скопировать файл русификации, или подправить sed’ом какой-нибудь исходник. Просто вызываете здесь cp , sed или ещё что-то. В качестве корня здесь выступает каталог, в который распаковался первый тарболл (за него отвечает переменная $RPM_BUILD_DIR, но она крайне редко используется).
При помощи %patch накладываются патчи. Если вы делали патч, как мы писали выше, то у вас всегда будет параметр -p1. Также часто используют параметр -b .название_патча , для создания резервной копии.
%build pushd %-tools-% %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 %-tools-% %makeinstall_std popd
%makeinstall_std
%find_lang %
% %find_lang , поиск файлов локализации. Параметром у неё является название файлов, которые будут лежать после установки в каталоге %/usr/share/locale/*/LC_MESSAGES/*.mo . Обычно оно соответствует % . Если это не так, пишите другое имя.
Во многих spec-файлах вы можете заметить выполнение команды rm -rf % или rm -rf $RPM_BUILD_ROOT в самом начале секции %install , а также секцию %clean с такими же строками. В современной РОСЕ в этом нет необходимости, такая зачистка выполняется автоматически.
%preun %preun_uninstall_gconf_schemas %
Секции для установочных скриптов. Вообще их бывает несколько. %pre — выполняется перед установкой, %post — после установки, %preun — перед удалением, %postun — после удаления. В нашем примере при удалении удаляются схемы Gconf. Здесь мы предполагаем, что в пакете только одна схема и ее имя совпадает с именем пакета. Обратите внимание, что для удаления схем мы вызываем специальный макрос; этот макрос раскрывается rpmbuild РОСЫ в набор необходимых команд оболочки Shell, которые, собственно, и удаляют схему. Установка схем при установке пакета выполняется автоматически за счет файловых триггеров RPM.
Для каждого пакета могут быть свои скрипты, поэтому следует также почитать документацию. Если никаких скриптов для правильной работы не нужно, то и секции эти не следует использовать. В этих секциях можно применять bash-скрипты (впрочем как и в любых других секциях).
В секциях %files мы должны указать какие файлы должны быть упакованы в пакеты. Все файлы должны быть оговорены, в противном случае rpmbuild выдаст сообщение о неупакованных файлах.
Опцией -f указываются файл, содержащий список обрабатываемых файлов. В нашем случае этот файл содержит пути к файлам локализации. Вы в принципе можете создать свой файл и подсунуть его.
Для определения каталогов используются специальные макроопределения.
- % — /usr
- % — /etc
- % — /usr/bin
- % — /usr/share
- % — /usr/lib или /usr/lib64 в зависимости от разрядности системы
- % — соответственно /lib или /lib64
- % — /usr/libexec
- % — / usr/unclude
- % — /usr/share/man
- % — /usr/sbin
- % — /var .
- % — /usr/lib/systemd
%files -f %.lang %defattr(-, root, root) %doc AUTHORS COPYING INSTALL README NEWS %/gconf/schemas/stardict.schemas %/stardict %/stardict-editor %/bonobo/servers/GNOME_Stardict.server %/applications/*.desktop %/stardict %/locale/*/LC_MESSAGES/* %/pixmaps/stardict.png %/gnome/help/%/* %/idl/GNOME_Stardict.idl %/omf/* %doc %/man?/*
%doc помечает файлы как документацию. Третья строка копирует указанные файлы в каталог %/doc/%-% . По умолчанию файлы в rpm пакете будут иметь владельцем root’а, а права доступа у низ будут такие же, как и в процессе установки. Если это необходимо поменять, то воспользуйтсь конструкцией %defattr .
Далее просто перечисляются файлы.
%files tools %/stardict-editor
Тоже самое для пакета stardict-tools . Если бы он назывался tools-stardict , то %files выглядел бы так:
%files -n tools-%.
Последнее, что идёт в spec-файле, это %changelog . В changelog’е вы указывает изменения в пакете по сравнению с предыдущей версией. Синтаксис его примерно следующий.
%changelog * Sun Apr 22 2007 Your Name - 2.4.8-4 - update desktop patch
Макроопределения
Теперь пора познакомиться поближе с макросами и переменными. Допустим, мы собираем пакет из SVN, в данном случае в релиз обычно включается дата ревизии. В самом начале spec-файла нужно определить переменную date:
%define date 20070612
Как мы видим, за определение переменных отвечает макроопределение %define . Теперь в любом месте spec-файла мы можем использовать нашу переменную в виде % (скобки не обязательны, но в РОСЕ принято брать в скобки переменные, и не брать — макроопределения; так их проще различать). Например, определение основных параметров будет выглядеть примерно так:
Version: 0.5 Release: 0.svn%.3
Обратите внимание, что перед датой стоит 0., а после даты — число, которое и увеличивается при необходимости поднять релиз. Зачем так сделано? Когда наконец выйдет окончательная версия (в нашем случае — 0.5), ревизию можно будет убрать, а в релиз прописать просто 1. При этом литерально 1 больше, чем любая строка, начинающаяся на 0, и пакет будет считаться более новым, чем предварительные пакеты, собиравшиеся на основе ревизий SVN.
Крайне популярным макроопределением является конструкция
%if условие действие1 %else действие2 %endif
или просто %if без %else . Суть проста, если условие стоящее при %if истина, то выполняется действие1 , в противном случае выполняется действие2 .
Допустим, мы опять же собираем что-нибудь из SVN. Обычно внутри архива, если он из SVN, вместо каталога %-% указывают просто % (архив sim-0.9.5.tar.bz2 внутри имеет каталог sim , так как финального релиза sim 0.9.5 не существует. Конечный же релиз будет иметь первым каталогом sim-0.9.5 ). Чтобы всякий раз не переписывать spec-файл, можно сделать следующие макроопределения:
%define svn 1 . %prep %if % %setup -q -n % %else %setup -q %endif
Если переменная svn не определена, то будет выполняться часть сценария после %else . Можно также использовать более строгое условие (не забудьте про кавычки):
%define svn 1 . %prep %if "%" == "1" %setup -q -n % %else %setup -q %endif
Внутри всех секций spec-файла мы можем использовать любые команды Linux, без каких либо «наворотов», а вот в шапке файла не всё так просто. Например, нам нужно определить версию firefox для пакета (допустим epiphany) и прописать ее в секцию Requires: . Выглядеть это будет следующим образом:
Requires: firefox = %(rpm -q firefox --qf "%%")
Обратите внимание на то, что внешняя команда выполняется в %() (почти, как в 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
Создание RPM-пакетов с нуля на примерах
Обновлено: 19.05.2023 Опубликовано: 15.07.2021
В данной инструкции мы научимся готовить Linux-среду для работы и рассмотрим примеры по созданию своих пакетов RPM. Также приведем описание файла SPEC, который используется для описания процесса сборки пакета. Мы будем работать в системе CentOS (Red Hat / Fedora).
Подготовка системы
Для работы по сборке пакетов лучше использовать отдельный компьютер, виртуальную машину или контейнер Docker. 1. Установим пакеты:
yum install rpmdevtools rpmlint
- rpmdevtools — позволит нам использовать утилиту rpmdev-setuptree, с помощью которой мы сможем создать рабочую среду в виде каталогов для сборки.
- rpmlint — позволяет протестировать пакет RPM.
yum group install «Development Tools»
* данная группа пакетов включает все необходимое для сборки. Ее не рекомендуется ставить на рабочий компьютер, так как устанавливается много ненужного для стандартной системы мусора.
2. Создаем пользователя.
Делать готовые установочные сборки пакетов очень опасно от пользователя root. Если мы допустим ошибку с путями, файлы могут перетереть или удалить важные для работы директории. Стоит создать отдельного пользователя и работать под ним. Однако, если мы работаем в виртуальной среде или контейнере Docker, нам это не страшно. Тогда данный пункт можно пропустить и работать из под root.
useradd builder -m
* в данном примере мы создадим пользователя builder. Опция -m сразу создаст домашний каталог для пользователя.
Теперь заходим под данным пользователем — последующие команды мы будем выполнять от него:
3. Создадим структуру каталогов для сборки:
В нашей текущем каталоге должна появиться папка rpmbuild — а в ней:
- BUILD — содержит все файлы, которые появляются при создании пакета.
- RPMS — сюда будут складываться готовые пакеты.
- SOURCES — для исходников, из которых и будут собираться RPM-пакеты.
- SPECS — для файлов с описанием процесса сборки.
- SRPMS — для исходников RPM-файлов.
Мы готовы к сборке.
Сборка из исходников
Рассмотрим пример создания RPM из пакета, который нужно собирать из исходников с помощью команды make. Например, возьмем данную программу: github.com/brettlaforge/pg_redis_pubsub.
Создадим файл spec:
Теперь откроем его и приведем к виду:
Name: pg_redis_pubsub
Version: 1.0.2
Release: 1%
Summary: Redis Publish from PostgreSQL
License: X11 License
URL: https://github.com/brettlaforge/pg_redis_pubsub
Source0: %-%.tar.gz
BuildRequires: postgresql-devel postgresql-server-devel
BuildRequires: hiredis-devel
Requires: postgresql
%if 0% < 8
Requires: hiredis-last >= 0.13.3-1
%else
Requires: hiredis = 0.15
%endif
%define _build_id_links none
%description
Redis Publish from PostgreSQL
%clean
% -rf $RPM_BUILD_ROOT
% -rf $RPM_BUILD_DIR/*
%files
%defattr(-,root,root)
%/pgsql/redis.so
%/pgsql/extension/redis.control
%/pgsql/extension/redis—0.0.1.sql
%doc %/doc/extension/redis.mmd
%changelog
* Fri Jul 9 2021 root
—
* чтобы понять, как заполнить spec-файл, рекомендуется для начала собрать и установить приложение вручную с помощью make и make install. Также необходимо изучить документацию устанавливаемого пакета или (при наличие возможности) поговорить с разработчиками программного обеспечения.
Установим зависимости, которые необходимы для сборки (BuildRequires):
* утилита yum-builddep сама читает зависимости, необходимые для сборки и устанавливает недостающие пакеты.
Можно это сделать и вручную. В данном примере это:
yum install epel-release
yum install postgresql-devel postgresql-server-devel hiredis-devel
* конкретно, в моем примере для установки hiredis-devel необходимо поставить репозиторий epel-release. Список пакетов, необходимый для сборки конкретного пакета необходимо уточнить в документации.
Теперь копируем исходник на свой компьютер. В моем примере клонируем репозиторий:
git clone https://github.com/brettlaforge/pg_redis_pubsub.git
Готовим архив и помещаем его в каталог rpmbuild/SOURCES:
tar -czvf rpmbuild/SOURCES/pg_redis_pubsub-1.0.2.tar.gz pg_redis_pubsub
Если бы в качестве Source мы указали внешний URL, можно было бы предварительно загрузить исходники командой:
spectool -g -R rpmbuild/SPECS/pg_redis_pubsub.spec
Данная команда разместит загруженные файлы в каталоге rpmbuild/SOURCES/.
Проверяем корректность SPEC-файла:
В моем примере команда вернула ответ:
rpmbuild/SPECS/pg_redis_pubsub.spec: W: invalid-url Source0: pg_redis_pubsub-1.0.2.tar.gz
0 packages and 1 specfiles checked; 0 errors, 1 warnings.
Данное предупреждение можно проигнорировать.
rpmbuild -bb rpmbuild/SPECS/pg_redis_pubsub.spec
Если она пройдет без ошибок, мы должны найти RPM-пакет в каталоге rpmbuild/RPMS/x86_64, где x86_64 — архитектура пакета.
Описание файла SPEC
Данный файл является инструкцией по сборке пакета. В нем мы описываем сам пакет, задаем метаданные и указываем, как извлекать файлы и куда их копировать при установке пакета. Синтаксис файла включает такие элементы, как разделы, макросы, операторы, опции. Рассмотрим их отдельно.
Опции заголовка
Определяют описание пакета, а также некоторые важные для сборки параметры.
Опция | Описание | Пример значения |
---|---|---|
Name | Название для пакета RPM | pg_redis_pubsub |
Version | Версия собираемого пакета | 1.0.2 |
Release | Релиз или версия программы | 1% ?dist обозначение версии доработки |
Summary | Краткое описание пакета | Redis Publish from PostgreSQL |
License | Способ лицензирования | X11 License |
URL | Адрес источника пакета | https://github.com/brettlaforge/pg_redis_pubsub |
Source0 | Источник данных, из которых должен собираться пакет. Можно указать несколько источников: Source1, Source2 . SourceN |
%-%.tar.gz Данная запись означает, что сборщик будет искать архив pg_redis_pubsub-1.0.2.tar.gz в каталоге rpmbuild/SOURCES/ |
BuildRequires | Требования к пакетам, которые нужны для сборки пакета. Можно написать большим списком, а можно добавить несколько отдельных строк BuildRequires. Также мы можем задать требование к версии пакета. | postgresql-devel postgresql-server-devel hiredis-devel |
Requires | Требования к пакетам, которые нужны для установки собранного пакета. Можно написать большим списком, а можно добавить несколько отдельных строк Requires. Также мы можем задать требование к версии пакета. С версии rpm 4.13 поддерживаются логические операторы and, or, if. | hiredis >= 0.13.3-1, (postgrespro-std-15-client or postgrespro-ent-15-client) |
Provides | Имя предоставляемого пакета. Данная опция важна для Requires других пакетов. Например, мы можем делать сборку пакета с разными назвваниями, которые зависят от версии или среды, но у всех этих пакетов будет общее поле Provides, таким образом, при зависимостях можно будет указать только данное общее значение. | pg_pubsub |
Obsoletes | Объявляет пакеты устаревшими. Установщик выполнит их удаление при установке собранного пакета. | hiredis < 0.13.3-1 |
Теги для определения переменных
С помощью тега %define можно определять переменные. Предоставлены разные возможности это сделать:
Пример определения | Описание |
---|---|
%define debug_package 1 | Простое создание переменной debug_package со значением 1. Обращение к данной перемнной возможно с помощью написания %. |
% | Данная переменная osname будет определена со значением redos, если она не определена ранее. |
Также мы можем определить переменную с помощью %global, например:
Такие переменные имеют глобавльный охват. Однако в настоящее время rpm не очищает область действия макросов и принципиальной разницы между global и define нет.
Основные рабочие разделы
В каждом разделе описывается своя часть логики процесса сборки пакета.
Раздел | Описание |
---|---|
%description | Описание пакета. Может состоять из нескольких строк, но каждая строка должна содержать до 73 символов. |
%package -n | Будет создан дополнительный пакет с именем . Для данного подраздела можно указать свои опции Summary, Requires и так далее. В одном файле spec можно указать сколько угодно данных разделов со своими поднастройками. Это значит, что при сборке будет созданно несколько пакетов с разными названиями. |
%description -n | Описание для создаваемого дополнительного пакета. |
%package devel | Добавленный devel указывает на то, что будет создан дополнительный пакет devel. |
%description devel | Описание для пакета devel. |
%prep | Предварительная обработка. Используется для подготовки исходников. Как правило, в данном разделе происходит их распаковка. Также на данном этапе могут применяться патчи. |
%build | Этап сборки пакета. Как правило, это make. |
%install | Установка пакета. Это может быть make install или копирование конкретных файлов в конкретные директории или запуск произвольного скрипта. |
%clean | Раздел содержит инструкции по удалению устаревших файлов, которые больше не нужны. |
%files | Перечисляем файлы, которые должны попасть в конечную систему при установке пакета. |
%files -n | Список файлов для дополнительного пакета. |
%files devel | Список файлов, которые должны войти в пакет devel. |
%changelog | Список изменений в работе программного обеспечения. |
Макросы разделов
У каждого из разделов могут быть свои макросы.
%files:
Макрос | Описание |
---|---|
Добавляем файл или каталог в пакет без указания дополнительных опций. | |
%doc | Указываем, что конкретные файлы относятся к документации. Такие файлы будут установлены в раздел /usr/doc/ |
%config | Помечаем файлы как конфигурационные. Это задает действие при удалении пакета — если файлы были изменены, они будут переименованы с добавлением .rpmsave. |
%dir | Обозначает директорию, которой владеет пакет. При удалении пакета, также будет удаляться данная директория. |
%files -f | Позволяет перечислить файлы во внешнем файле и передать его как аргумент. |
%defattr(,,,) | Задаем права для файлов и каталогов, которые будут назначены при установке пакета. Данный макрос применяется глобально ко всем файлам. Например: %defattr(644,root,root). |
%attr(,,) | Задаем права на файл или каталог, которые должны быть назначены при установке пакета. Данный макрос применяется к конкретному перечню файлов. Например: %attr(644,postgres,postgres) %/pgsql/redis.so. |
%attr(,,) %config(noreplace) | В данном примере мы зададим и атрибут, и укажем, что файл является конфигурационным. |
%license | Указываем, что файл является файлом лицензии. |
Сценарии
Мы можем описать команды, которые будут выполняться на конечном компьютере при установке или удалении пакета:
Сценарий | Описание |
---|---|
%pre | Выполняется перед установкой пакета в систему |
%post | Выполняется после установки пакета в систему |
%preun | Выполняется перед удалением пакета из системы |
%postun | Выполняется после удаления пакета из системы |
Пример для %post
%post
case «$1» in
1)
post_install.sh
;;
*)
echo «postinst called with unknown argument \`$1′» >&2
exit 1
;;
esac
exit 0
* макрос %post принимает аргумент $1, который говорит нам как был установлен пакет — новая установка (1) или обновление (2). Это важно, так как действия, как правило, отличаются, в зависимости от того, чистая это установка или обновление.
Макросы для сценариев
Внутри сценариев могут быть запущены свои макросы:
Сценарий | Макрос | Описание |
---|---|---|
%post | %systemd_post | Запускается процедура установки и регистрации сервиса. |
%preun | %systemd_preun | Запрещается автозапуск сервиса (systemctl —no-reload disable . ) |
%postun | %systemd_postun_with_restart | Отмечает сервис для перезагрузки |
Макросы для команд
Некоторые системные команды лучше писать не напрямую, а через макросы. Это позволит добиться большей стабильности при сборке на различных системах. Приведем в пример данные команды:
Макрос | Команда | Описание |
---|---|---|
% | rm | Удаление файлов |
% | mv | Перенос файлов |
% | tar | Распаковка или создание архивов формата gz |
% | unzip | Распаковка архивов формата zip |
% | sed | Поиск по шаблону текста и его замена |
% | ln -s | Создание симлинка |
% | mkdir | Создание каталога |
% | mkdir -p | Рекурсивное создание каталога (создает папки по пути) |
% | chmod | Назначение прав доступа на файл или каталог |
% | chown | Назначение владельца на файл или каталог |
* полный список макросов можно получить командой rpm —showrc.
Макросы для каталогов
Каталоги лучше писать не буквально, а через макросы:
Макрос | Путь | Итоговый путь |
---|---|---|
% | /usr | /usr |
% | /usr | /usr |
% | %/lib64 | /usr/lib64 |
% | %/share | /usr/share |
% | % | /usr/share |
% | /etc | /etc |
% | /var | /var |
% | /var | /var |
% | /var/lib | /var/lib |
% | %/doc | /usr/share/doc |
% | /usr/lib/systemd/system | /usr/lib/systemd/system |
% | % | /usr |
% | %/bin | /usr/bin |
% | %/sbin | /usr/sbin |
* обратите внимание, что некоторые макросы ведут не на конкретные пути, а на другие макросы.
* полный список макросов можно получить командой rpm —showrc.
Раздел %files
Стоит немного подробнее рассмотреть раздел %files. В нем мы описываем файлы, которые должны быть упакованы в пакет. Приведем пример:
%files
%defattr(0640,postgres,postgres,0750)
%attr(0644,postgres,postgres) %/pgsql/redis.so
%/pgsql/extension/redis.control
%/pgsql/extension/redis—0.0.1.sql
%attr(0640,root,root) %doc %/doc/extension/redis.mmd
%config(noreplace) %/redis_ext.conf
* в данном примере:
- По умолчанию всем файлам присваиваются права 0640, каталогам — 0750. В качестве пользователя-владельца по умолчанию назначается postgres.
- Для файла redis.so мы решили поменять права на 0644.
- Файлу redis.mmd будет назначен владелец root.
- Файл redis_ext.conf обозначен как конфигурационный файл и он не будет заменяться при обновлении пакета.
Служебные переменные
Ранее мы рассмотрели возможность определения переменных в файле spec с помощью директив %define или %global. Переменные могут нами использовать для подстановки значений в определенные блоки сценария. Но также, мы можем определять некоторую логику с помощью специальных переменных. Рассмотрим это на конкретных примерах:
Переменная | Описание | Варианты |
---|---|---|
debug_package | Определяем необходимость создания пакета debuginfo (с отладочной информацией). | По умолчанию значение 1 и при сборке пакета также собирается пакет с суффиксом debuginfo. При значении % сборка проходит без создания debuginfo. |
_build_id_links | Позволяет указать, нужно ли создавать идентификаторы сборки в /usr/lib. | Если не указан, то сборка будет выполняться с созданием идентификаторов. Если задать значение none, то идентификаторы создаваться не будут. |
__brp_check_rpaths | При создании пакета rpmbuild проверяет пути библиотек с помощью check-rpaths. Данная опция позволяет указать, нужно ли это делать. | Для отключения проверки путей задаем переменную со значением %. |
Дополнительные опции
В файле spec могут быть указаны дополнительные настройки. Это просто опции, которые записываются как директивы конфигурационных файлов со своими значениями.
Опция | Описание | Значения |
---|---|---|
AutoReqProv | Указывает, нужно ли делать автоматическую обработку зависимостей RPM. | yes/no или 1/0. |
Операторы сравнения
SPEC файл позволяет задавать логику с помощью операторов сравнения. Приведем примеры их использования:
Пример | Описание |
---|---|
%if 0% < 8 Requires: hiredis-last >= 0.13.3-1 %else Requires: hiredis %endif |
В данном примере мы проверяем версию системы, на которой идет сборка. Если rhel (релиз системы) меньше 8, то мы указываем в качестве требования hiredis-last. В данном примере это имеет смысл, так как в CentOS 8 пакет hiredis-last переименовали в hiredis. |
%if 0% == 8 . %endif |
В данном условии мы проверяем, является ли версия релиза 8. |
%if % != «el» . %endif |
Проверяем значение переменной osname. Если она не равна «el», выполняем действие. |
Возможные ошибки
Рассмотрим примеры ошибко, с которыми мы можем столкнуться.
Installed (but unpackaged) file(s) found
Ошибка появляется в конце процесса сборки пакета.
Причина: обнаружены файлы, которые были установлены с помощью make install, но которые не были перечислены в %files. Таким образом, сборщик пакета не знает, что с ними делать.
Решение: секция %files должна содержать все файлы, необходимые для работы приложения. Их нужно перечислить.
Но если у нас есть полная уверенность, что мы перечислили все необходимое, а оставшиеся файлы нам ни к чему, то добавляем в файл spec:
%define _unpackaged_files_terminate_build 0
Как создать rpm пакет
Как уже отмечалось, весь Linux состоит из пакетов. В RedHat работу с пакетами выполняет программа rpm (RedHat Package Manager), а сами файлы, содержащие пакеты, имеют расширение .rpm . Кроме RedHat существует еще несколько дистрибутивов Linux, использующих rpm ; самые известные — Caldera, SuSE и KSI. Их так и называют — rpm-системы.
Сразу после установки системы зачастую возникает необходимость доставить некоторые пакеты, забытые при инсталляции, или убрать лишние.
У файлов, содержащих пакеты, всегда перед расширенем .rpm есть еще одно, обозначающее архитектуру, для которой предназначен этот пакет.
Некоторые расширения .rpm-файлов
Расширение | Назначение |
---|---|
.i386.rpm | Пакет для Linux/Intel |
.src.rpm | Исходный код пакета (никогда не устанавливайте .src.rpm — потом не удалите!) |
.alpha.rpm | Пакет для Linux/Alpha |
.sparc.rpm | Пакет для Linux/Sparc (Sun) |
.ppc.rpm | Пакет для Linux/PowerPC |
.noarch.rpm | Пакет для всех архитектур (обычно содержит данные — файлы конфигурации, шрифты и т.д.) |
Кроме того, само имя пакета состоит из собственно названия и версии. Например, lynx-2.8.2-3.i386.rpm — программа lynx , версия 2.8.2, build 3. К сожалению, формальных правил, позволяющих понять, где кончается имя и начинается версия, нет.
Файлы пакетов обычно расположены в одном из трех мест — в дистрибутиве, в разделе дополнений (updates) или в резделе «пожертвований» (contrib). В ИЯФ для RedHat 5.2/Intel это соответственно
Пакеты с исходными кодами всегда лежат в директориях SRPMS/ , и содержат исходный код для всех архитектур.
Использование rpm
Хотя rpm выполняет все функции работы с пакетами (включая создание .i386.rpm из .src.rpm), сейчас рассмотрим лишь основные действия.
Установка. Для установки пакета используется команда rpm -i (Install), которой указывается полное имя файла, содержащего пакет. Пример:
Если пакет уже установлен, rpm откажется его устанавливать. Если же это новая версия (т.е. делается не установка, а обновление), то надо воспользоваться командой rpm -U (Upgrade); фирма RedHat рекомендует «для красоты» использовать форму rpm -Uvh — при этом «прогресс» в установке показывается индикатором из символов » # «. Пример:
bobby:~# rpm -Uvh wu-ftpd-2.4.2b18-2.1.i386.rpm wu-ftpd ################################################## bobby:~# _
Если требуется установить несколько пакетов, то можно указать их все в одной команде (через пробелы). Иногда это нужно — например, при обновлении программы, состоящей из нескольких пакетов (например, Netscape), чтобы rpm не выдавал ошибок из-за зависимостей пакетов.
Удаление. Для удаления установленного пакета используется команда rpm -e (Erase). Ей указывается имя пакета (можно без версии), и без суффикса «.i386.rpm» . Пример:
При удалении нескольких пакетов их также стоит указать все вместе в одной команде, чтобы rpm не «ругался» на удаление пакета, от которого зависит другой пакет.
Информация. Чтобы узнать, установлен ли некий пакет, служит команда rpm -q (Query). Ей также указывается имя пакета, а она выдает его полное имя, если он установлен. Примеры:
bobby:~# rpm -q lynx lynx-2.8.1-5 bobby:~# rpm -q seyon package seyon is not installed bobby:~# _
Маленькие и заглавные буквы в именах пакетов различаются. Поскольку часто не помнишь точное имя пакета (и уж тем более, какие буквы там на каком регистре), можно воспользоваться командой rpm -qa (Query All packages — показать все пакеты) в сочетании с командой grep :
bobby:~# rpm -qa | grep -i after AfterStep-1.5-0.7 AfterStep-APPS-1.5-0.3 bobby:~# _
Сборка rpm пакета с помощью rpmbuild
Для сборки rpm-пакета в системе должен быть установлен rpm-build. Проверить его наличие можно следующей командой:
$ rpmbuild --version
Если система возвращает: rpmbuild: команда не найдена, значит rpm-build не установлен. Для установки необходимо выполнить следующую команду:
$ sudo yum install rpm-build
Структура команды для сборки должна выглядеть так:
rpmbuild [ПАРАМЕТР…]
Основные параметры сборки:
• -ba – Сборка исходного(.src.rpm) и двоичного(.rpm) пакетов
• -bb – Сборка только двоичного пакета(.rpm)
• -bs – Сборка только пакета с исходниками(.src.rpm)
Остальные параметры можно посмотреть с помощью команды:
$ rpmbuild --help
Сборка пакета
Установив необходимые библиотеки, а также положив в папку SOURCES — исходные файлы и в папку SPECS — файл конфигурации(.spec), можно приступать к сборке. Подробнее о том, что необходимо для сборки RPM пакета, можно узнать здесь
Находясь в каталоге SPECS необходимо выполнить следующую команду:
$ rpmbuild -ba ваш_spec_файл.spec
Результатом выполнения данной команды (если на предыдущих этапах всё было сделано правильно) будет собранный пакет, и в каталоге RPMS появятся бинарный пакет (ваш_пакет.rpm), а в каталоге SRPMS — исходник (ваш_пакет.src.rpm).
Если на выходе нужно получить только .rpm файл или только .src.rpm, то -ba необходимо заменить на -bb или -bs соответственно.
Также RPM пакет можно создать с помощью утилиты mock, подробнее здесь