Примеры создания пакетов RPM из исходников или со своими файлами

Обновлено Обновлено: Опубликовано Опубликовано:

В данной инструкции мы научимся готовить Linux-среду для работы и рассмотрим примеры по созданию своих пакетов RPM. Мы будем работать в системе 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 сразу создаст домашний каталог для пользователя.

Теперь заходим под данным пользователем — последующие команды мы будем выполнять от него:

su — builder

3. Создадим структуру каталогов для сборки:

rpmdev-setuptree

В нашей текущем каталоге должна появиться папка rpmbuild — а в ней:

  1. BUILD — содержит все файлы, которые появляются при создании пакета.
  2. RPMS — сюда будут складываться готовые пакеты.
  3. SOURCES — для исходников, из которых и будут собираться RPM-пакеты.
  4. SPECS — для файлов с описанием процесса сборки.
  5. SRPMS — для исходников RPM-файлов.

Мы готовы к сборке.

Сборка из исходников

Рассмотрим пример создания RPM из пакета, который нужно собирать из исходников с помощью команды make. Например, возьмем данную программу: github.com/brettlaforge/pg_redis_pubsub.

Создадим файл spec:

rpmdev-newspec rpmbuild/SPECS/pg_redis_pubsub.spec

Теперь откроем его и приведем к виду:

vi rpmbuild/SPECS/pg_redis_pubsub.spec

Name:           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:        %{name}-%{version}.tar.gz

BuildRequires:  postgresql-devel postgresql-server-devel
BuildRequires:  hiredis-devel
Requires:       postgresql
%if 0%{?rhel} < 8
Requires:       hiredis-last >= 0.13.3-1
%else
Requires:       hiredis = 0.15
%endif

%define         _build_id_links none

%description
Redis Publish from PostgreSQL

%prep
%{__rm} -rf %{name}-%{version}
%{__mkdir} -p %{name}-%{version}
%{__tar} -xzvf %{SOURCE0} -C %{_builddir}/%{name}-%{version} —strip-components 1

%build
cd %{name}-%{version}
%{__make}

%install
cd %{name}-%{version}
%{__make} install DESTDIR=%{buildroot}

%clean
%{__rm} -rf $RPM_BUILD_ROOT
%{__rm} -rf $RPM_BUILD_DIR/*

%files
%defattr(-,root,root)
%{_libdir}/pgsql/redis.so
%{_datadir}/pgsql/extension/redis.control
%{_datadir}/pgsql/extension/redis—0.0.1.sql
%doc %{_datadir}/doc/extension/redis.mmd

%changelog
* Fri Jul  9 2021 root

* чтобы понять, как заполнить spec-файл, рекомендуется для начала собрать и установить приложение вручную с помощью make и make install. Также необходимо изучить документацию устанавливаемого пакета или (при наличие возможности) поговорить с разработчиками программного обеспечения.

Установим зависимости, которые необходимы для сборки (BuildRequires):

yum-builddep rpmbuild/SPECS/pg_redis_pubsub.spec

* утилита 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-файла:

rpmlint rpmbuild/SPECS/pg_redis_pubsub.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}
?dist обозначение версии доработки
Summary Краткое описание пакета Redis Publish from PostgreSQL
License Способ лицензирования X11 License
URL Адрес источника пакета https://github.com/brettlaforge/pg_redis_pubsub
Source0 Источник данных, из которых должен собираться пакет.
Можно указать несколько источников: Source1, Source2 … SourceN
%{name}-%{version}.tar.gz
Данная запись означает, что сборщик будет искать архив 
pg_redis_pubsub-1.0.2.tar.gz в каталоге rpmbuild/SOURCES/
BuildRequires Требования к пакетам, которые нужны для сборки пакета.
Можно написать большим списком, а можно добавить несколько отдельных строк BuildRequires.
Также мы можем задать требование к версии пакета.
postgresql-devel postgresql-server-devel hiredis-devel
Requires Требования к пакетам, которые нужны для установки собранного пакета.
Можно написать большим списком, а можно добавить несколько отдельных строк Requires.
Также мы можем задать требование к версии пакета.
hiredis >= 0.13.3-1
Obsoletes Объявляет пакеты устаревшими. Установщик выполнит их удаление при установке собранного пакета. hiredis < 0.13.3-1

Теги для определения переменных

С помощью тега %define можно определять переменные. Предоставлены разные возможности это сделать:

Пример определения Описание
%define debug_package 1 Простое создание переменной debug_package со значением 1. Обращение к данной перемнной возможно с помощью написания %{debug_package}.
%{!?osname: %define osname «redos»} Данная переменная osname будет определена со значением redos, если она не определена ранее.

Основные рабочие разделы

В каждом разделе описывается своя часть логики процесса сборки пакета.

Раздел Описание
%description Описание пакета. Может состоять из нескольких строк, но каждая строка должна содержать до 73 символов.
%prep Предварительная обработка. Используется для подготовки исходников. Как правило, в данном разделе происходит их распаковка. Также на данном этапе могут применяться патчи.
%build Этап сборки пакета. Как правило, это make.
%install Установка пакета. Это может быть make install или копирование конкретных файлов в конкретные директории или запуск произвольного скрипта.
%clean Раздел содержит инструкции по удалению устаревших файлов, которые больше не нужны.
%files Перечисляем файлы, которые должны попасть в конечную систему при установке пакета.
%changelog Список изменений в работе программного обеспечения.

Макросы разделов

У каждого из разделов могут быть свои макросы:

Раздел Макрос Описание
%files %doc Указываем, что конкретные файлы относятся к документации. Такие файлы будут установлены в раздел /usr/doc/
%config Помечаем файлы как конфигурационные. Это задает действие при удалении пакета — если файлы были изменены, они будут переименованы с добавлением .rpmsave.
%dir Обозначает директорию, которой владеет пакет. При удалении пакета, также будет удаляться данная директория.
%files -f Позволяет перечислить файлы во внешнем файле и передать его как аргумент.
%defattr(<mode>,<user>,<group>) Задаем права для файлов и каталогов, которые будут назначены при установке пакета. Данный макрос применяется глобально ко всем файлам. Например: %defattr(644,root,root).
%attr(<mode>,<user>,<group>) Задаем права, которые должны быть назначены при установке пакета. Данный макрос применяется к конкретному перечню файлов. Например: %attr(644,postgres,postgres) %{_libdir}/pgsql/redis.so.

Сценарии

Мы можем описать команды, которые будут выполняться на конечном компьютере при установке или удалении пакета:

Сценарий Описание
%pre  Выполняется перед установкой пакета в систему
%post Выполняется после установки пакета в систему
%preun Выполняется перед удалением пакета из системы
%postun Выполняется после удаления пакета из системы

Макросы для сценариев

Внутри сценариев могут быть запущены свои макросы:

Сценарий Макрос Описание
%post %systemd_post Запускается процедура установки и регистрации сервиса.
%preun  %systemd_preun Запрещается автозапуск сервиса (systemctl —no-reload disable …)
%postun %systemd_postun_with_restart Отмечает сервис для перезагрузки

Макросы для команд

Некоторые системные команды лучше писать не напрямую, а через макросы. Это позволит добиться большей стабильности при сборке на различных системах. Приведем в пример данные команды:

Макрос Команда Описание
%{__rm}  rm Удаление файлов
%{__mv} mv Перенос файлов
%{__tar} tar Распаковка или создание архивов формата gz
%{__unzip} unzip Распаковка архивов формата zip
%{__sed} sed Поиск по шаблону текста и его замена
%{__ln_s} ln -s Создание симлинка
%{__mkdir} mkdir Создание каталога
%{__mkdir_p} mkdir -p Рекурсивное создание каталога (создает папки по пути)

* полный список макросов можно получить командой rpm —showrc.

Макросы для каталогов

Каталоги лучше писать не буквально, а через макросы:

Макрос Путь
%{_prefix} /usr
%{_usr} /usr
%{_libdir}  %{_prefix}/lib64
%{_datarootdir} %{_prefix}/share
%{_datadir} %{_datarootdir}
%{_sysconfdir} /etc
%{_var} /var
%{_localstatedir} /var
%{_sharedstatedir} /var/lib

* обратите внимание, что некоторые макросы ведут не на конкретные пути, а на другие макросы.
* полный список макросов можно получить командой rpm —showrc.

Операторы сравнения

SPEC файл позволяет задавать логику с помощью операторов сравнения. Приведем примеры их использования:

Пример Описание
%if 0%{?rhel} < 8
Requires:       hiredis-last >= 0.13.3-1
%else
Requires:       hiredis
%endif
В данном примере мы проверяем версию системы, на которой идет сборка. Если rhel (релиз системы) меньше 8, то мы указываем в качестве требования hiredis-last. В данном примере это имеет смысл, так как в CentOS 8 пакет hiredis-last переименовали в hiredis.
%if 0%{?rhel} == 8

%endif
В данном условии мы проверяем, является ли версия релиза 8.
%if %{?osname} != «el»

%endif
Проверяем значение переменной osname. Если она не равна «el», выполняем действие.

Возможные ошибки

Рассмотрим примеры ошибко, с которыми мы можем столкнуться.

Installed (but unpackaged) file(s) found

Ошибка появляется в конце процесса сборки пакета.

Причина: обнаружены файлы, которые были установлены с помощью make install, но которые не были перечислены в %files. Таким образом, сборщик пакета не знает, что с ними делать.

Решение: секция %files должна содержать все файлы, необходимые для работы приложения. Их нужно перечислить.

Но если у нас есть полная уверенность, что мы перечислили все необходимое, а оставшиеся файлы нам ни к чему, то добавляем в файл spec:

%define _unpackaged_files_terminate_build 0

* в верхнюю часть.