1. Структура spec-файла: Основные разделы и базовый синтаксис
Структура spec-файла: Основные разделы и базовый синтаксис
В предыдущем модуле мы разобрали архитектуру RPM и поняли, как пакетный менеджер взаимодействует с системой. Теперь пришло время спуститься на уровень разработчика и научиться создавать пакеты. Сердцем любого RPM-пакета является spec-файл (spec file от слова specification). Это текстовый документ, который содержит пошаговую инструкцию: откуда взять исходный код, как его подготовить, как скомпилировать и какие файлы в итоге нужно упаковать в готовый архив.
Если RPM-пакет — это готовое блюдо, то исходный код — это ингредиенты, а spec-файл — это подробный кулинарный рецепт. В этой статье мы разберём анатомию этого «рецепта», изучим базовый синтаксис и научимся писать спеки, соответствующие стандартам Rosa Linux.
Общая архитектура spec-файла
Spec-файл имеет строгую, исторически сложившуюся структуру. Он читается сверху вниз и делится на две логические части:
%prep, %build).!Жизненный цикл исходного кода внутри spec-файла
Давайте рассмотрим минимальный рабочий пример spec-файла для вымышленной утилиты hello-world, а затем разберём каждую его строку под микроскопом.
На первый взгляд код может показаться набором заклинаний, но за каждым тегом стоит чёткая логика.
Преамбула: Паспорт вашего пакета
Преамбула не имеет специального открывающего тега. Она начинается с первой строки файла и содержит пары «Ключ: Значение». Это паспортные данные пакета, которые пользователь увидит при выполнении команды rpm -qi имя_пакета.
Основные теги метаданных
Name — базовое имя пакета. Оно должно состоять из строчных букв, цифр и дефисов. Избегайте нижних подчеркиваний.Version — версия программы (апстрим-версия), точно совпадающая с версией разработчика исходного кода. В версии запрещено использовать дефисы, так как RPM использует дефис для отделения версии от релиза.Release — номер сборки (релиза) пакета для текущей версии. Если вы изменили spec-файл, но версия программы осталась прежней (например, добавили патч или исправили зависимость), вы увеличиваете Release (1, 2, 3...). При обновлении Version значение Release сбрасывается обратно в 1.Summary — краткое описание пакета. Строго в одну строку, без точки на конце. Это то, что пользователи видят при поиске пакетов.License — лицензия, под которой распространяется код. В Rosa Linux принято использовать короткие идентификаторы стандарта SPDX (например, GPL-2.0-or-later, MIT, Apache-2.0).URL — ссылка на домашнюю страницу проекта.Исходники и патчи
Source0 — имя архива с исходным кодом. Обычно это tar-архив (.tar.gz, .tar.xz). Цифра 0 означает, что это первый (и часто единственный) исходник. Если программе нужны дополнительные файлы (иконки, конфигурации по умолчанию), их добавляют как Source1, Source2 и так далее.Patch0 — файл с изменениями (патч), который нужно применить к исходному коду перед сборкой. Патчи используются для исправления ошибок или адаптации программы под специфику Rosa Linux без изменения оригинального архива Source0.Зависимости: BuildRequires против Requires
Это один из самых важных аспектов, в котором новички часто допускают ошибки.
BuildRequires — пакеты, необходимые только для сборки программы. Например: компиляторы (gcc, clang), системы сборки (cmake, meson), заголовочные файлы библиотек (pkgconfig(gtk+-3.0), openssl-devel). Эти пакеты устанавливаются в сборочной среде (на серверах ABF) и не тянутся на компьютер конечного пользователя.Requires — пакеты, необходимые для работы уже установленной программы. Например, если ваша утилита написана на Python, ей нужен интерпретатор Python для запуска. > Важное правило: Современный RPM очень умён. Он автоматически анализирует скомпилированные бинарные файлы и сам прописывает зависимости от системных библиотек (например, libc.so.6). Поэтому в Requires нужно указывать только неочевидные зависимости (скрипты, внешние утилиты, специфические шрифты), которые RPM не может определить автоматически.
Макросы: Переменные мира RPM
Вы наверняка заметили в примере конструкции вида %{name} или %{_bindir}. Это макросы — встроенные переменные RPM.
Макросы решают три критически важные задачи:
hello-world в теге Name, вам не нужно писать hello-world-1.0.tar.gz в Source0. Вы пишете %{name}-%{version}.tar.gz. При изменении версии вам нужно будет обновить только одну строку в преамбуле./usr/lib, а в Rosa Linux — в /usr/lib64. Базовые макросы путей
Никогда не используйте жестко заданные пути (хардкод) в spec-файлах. Всегда используйте макросы:
| Жесткий путь (Неправильно) | Макрос (Правильно) | Назначение |
| :--- | :--- | :--- |
| /usr/bin | %{_bindir} | Исполняемые файлы (бинарники) |
| /usr/lib64 или /usr/lib | %{_libdir} | Системные библиотеки |
| /etc | %{_sysconfdir} | Конфигурационные файлы |
| /usr/share/doc | %{_docdir} | Документация |
| /usr/share/man | %{_mandir} | Руководства (man pages) |
Секция %prep: Подготовка плацдарма
Секция %prep (от preparation) — это первый этап реальной работы. Здесь исходный код распаковывается из архива Source0 и подготавливается к компиляции. На этом этапе применяются патчи.
Исторически для распаковки использовался макрос %setup -q. Однако в современных спеках Rosa Linux стандартом де-факто стал макрос %autosetup.
Что делает %autosetup -p1 под капотом?
Source0.Patch0, Patch1 и т.д. в преамбуле и применяет их к исходному коду с параметром -p1 (отбрасывая первый уровень вложенности путей в патче, что является стандартом для git-патчей).Секция %build: Превращение кода в программу
В секции %build происходит магия компиляции. Здесь исходный код превращается в исполняемые бинарные файлы. Содержимое этой секции напрямую зависит от того, какую систему сборки использует разработчик программы (Autotools, CMake, Meson, Ninja, чистый Makefile).
Для классических программ на C/C++, использующих Autotools (скрипт configure), секция выглядит так:
Почему мы используем макрос %configure, а не пишем ./configure напрямую?
Макрос %configure автоматически подставляет десятки параметров, специфичных для Rosa Linux. Он указывает правильные пути (--prefix=/usr, --libdir=/usr/lib64), а также передает системные флаги компилятора (CFLAGS, CXXFLAGS, LDFLAGS), которые обеспечивают оптимизацию под архитектуру процессора и включают защиту от уязвимостей (например, ASLR и Stack Smashing Protection).
Макрос %make_build заменяет обычный вызов make. Его главное преимущество — он автоматически определяет количество ядер процессора на сборочном сервере и запускает параллельную сборку (эквивалент make -j8), что ускоряет процесс в разы.
Секция %install: Сборочный корень (Buildroot)
Секция %install — самая сложная для понимания концепция среди новичков.
Когда программа скомпилирована, её нужно «установить». Но если мы выполним стандартную команду make install, программа попытается установиться прямо в системные директории сборочного сервера (в /usr/bin, /etc и т.д.). Это приведет к хаосу: файлы пакета смешаются с файлами системы, и мы не сможем собрать их в RPM-архив. Более того, у процесса сборки обычно нет root-прав для записи в /usr.
Для решения этой проблемы используется сборочный корень (buildroot). Это временная, изолированная директория (песочница), которая эмулирует корневую файловую систему /.
В секции %install мы устанавливаем программу не в реальную систему, а в этот сборочный корень.
Макрос %make_install эквивалентен команде make install DESTDIR=%{buildroot}. Программа думает, что устанавливается в /usr/bin/hello-world, но физически файл копируется во временную папку, например: /home/builder/rpmbuild/BUILDROOT/hello-world-1.0-1.x86_64/usr/bin/hello-world.
> Важно: Секция %install не устанавливает пакет на ваш компьютер! Она лишь формирует структуру папок и файлов внутри временной директории, из которой RPM-утилита затем запакует архив.
Секция %files: Опись имущества
После того как файлы помещены в buildroot, RPM должен знать, какие именно файлы нужно включить в итоговый пакет. Этим занимается секция %files.
Если файл есть в buildroot, но не указан в %files, сборка завершится с ошибкой (ошибка unpackaged files found). Это механизм защиты: вы не должны случайно забыть упаковать нужный файл или упаковать лишний мусор.
Специальные директивы в %files
%license — помечает файл как лицензионное соглашение. RPM установит его в специальную системную директорию для лицензий.%doc — помечает файл как документацию (README, CHANGELOG). %config(noreplace) — критически важный макрос для конфигурационных файлов (обычно в /etc). Флаг noreplace говорит пакетному менеджеру: «Если пользователь изменил этот файл на своем компьютере, при обновлении пакета не перезаписывай его новым дефолтным файлом». Вместо этого новый файл будет сохранен с расширением .rpmnew.Управление директориями
Существует огромная разница между указанием директории и указанием файлов внутри неё.
Если вы напишете:
%{_datadir}/hello-world/
RPM упакует саму директорию hello-world и абсолютно все файлы и поддиректории внутри неё. Это удобно для папок, которые целиком принадлежат вашей программе.
Но если вы напишете:
%{_bindir}
Это катастрофическая ошибка! Вы прикажете RPM стать владельцем всей системной папки /usr/bin и всех программ в ней. Пакет будет конфликтовать с базовой системой.
Если вам нужно создать пустую директорию, принадлежащую пакету, используйте директиву %dir:
%dir %{_sysconfdir}/hello-world
Секция %changelog: История изменений
В самом конце spec-файла находится секция %changelog. Это журнал изменений пакета (не путать с changelog самой программы). Здесь мейнтейнеры записывают, кто, когда и зачем изменил spec-файл.
Формат записи строго регламентирован:
Например:
* Mon Oct 23 2023 Ivan Ivanov <ivan@example.com> - 1.0-2
- Добавлен патч для исправления падения при запуске
Типичные ошибки новичков
rm -rf / в секции %install вместо %install_root) может уничтожить вашу систему. Сборка всегда должна происходить от обычного пользователя.wget или npm install (без предварительно подготовленного кэша) в секции %build завершатся ошибкой. Все исходники должны быть скачаны заранее и указаны в Source.rpmlint. Она укажет на хардкод путей, неправильные права доступа и отсутствующие макросы.В следующей статье мы подробно погрузимся в управление зависимостями: научимся разрешать конфликты библиотек, использовать виртуальные пакеты и правильно связывать компоненты системы между собой.