Сборка пакета с нуля
Данное руководство покажет, как правильно собрать пакет RPM в Sisyphus с нуля в инфраструктуре Gear и git.alt, имея только исходный код пакета, и права мейнтейнера на git.alt. В качестве примера опакетим KChildlock, чтобы закрыть запрос на сборку в багзилле: https://bugzilla.altlinux.org/25796.
Введение
Для сборки пакетов подразумеваются следующие начальные условия:
- У вас установлен дистрибутив ALT Linux;
- Есть желание собрать пакет правильно, а не для единичного случая;
- Вы носите гордое звание «мейнтейнер ALT Linux Team», что подразумевает наличие электронных ключей и доступа к инфраструктуре git.alt
Третий пункт необязателен для новичков, которые просто хотят собрать пакет правильно для себя.
В ALT Linux используется формат пакетов RPM, который представляет собой архив, содержащий архив с устанавливаемыми или собираемыми файлами и заголовок с метаинформацией (например, название, версия, группа и т.п.). Различают два вида пакетов RPM:
- Пакет с исходным кодом (имеет расширение .src.rpm). Такой пакет содержит архив (один или несколько) с исходным кодом, файл Spec (далее — просто спек) и, возможно, разнообразные патчи и дополнения. Пакет src.rpm можно использовать только для сборки двоичных пакетов, но не установки. Сборка осуществляется командой:
rpmbuild --rebuild package...src.rpm
- Собранный двоичный пакет (имеет расширение вида <архитектура>.rpm). В качестве архитектуры может быть i586, x86_64 или noarch. Такие пакеты можно устанавливать командой
rpm -Uvh package...rpm
Подробную информацию по структуре RPM и сборке с помощью команды rpm можно найти в Maximum RPM.
Однако для сборки через rpmbuild возникают очевидные сложности:
- Необходимо вручную удовлетворить сборочные зависимости для сборки (поставить компилятор, включаемые файлы, библиотеки). При большом количестве собираемых пакетов система засоряется.
- Для сборки пакета нужно сформировать .src.rpm из файлов, разбросанных по разным каталогам (по умолчанию, это подкаталоги SOURCE, SPECS и подкаталоги для сборки в ~/RPM).
- Файлы с исходным кодом должны лежать в упакованном виде, что делает трудоёмким процесс изготовления патчей.
- На рабочей системе можно упустить необходимое и достаточное количество зависимостей.
Чтобы избежать этих сложностей, в ALT Linux Team было придумано две технологии:
- Hasher для сборки в изолированном окружении. В chroot ставится базовый комплект пакетов и пакеты, необходимые для сборки (поле BuildRequires в спеке). Если какой-то пакет для сборки не указан в спеке, то появится ошибка. Так обеспечивается чистота сборки. Обратной стороной является необходимость иметь доступ к репозиторию, так как пакеты ставятся при каждой сборке в Hasher.
- Gear для сборки пакетов из репозитория Git. В этом случае все файлы лежат в распакованном виде и в src.rpm упаковываются по правилам, определённым в .gear/rules. Это позволяет работать сразу с содержимым, быстро делать патчи, вести историю изменений и обмениваться изменениями при коллективной разработке.
Установка пакетов для сборки
Для сборки нам потребуются следующие компоненты:
- Любой удобный текстовый редактор (наиболее удобными являются Vim и Emacs);
- Система управления версиями Git
- Сборочная среда Hasher
- Инфраструктура Gear
- Доступ к репозиторию пакетов
Для этого настройте репозитории и установите пакеты build-environment и gear:
apt-get install build-environment gear
Будут установлены с зависимостями все необходимые пакеты для опакечивания и сборки
Настройка среды
Окружение Git
git config --global user.name 'Andrey Cherepanov' git config --global user.email 'cas@altlinux.org' git config --global user.signingkey 'A9EBF131'
Измените в зависимости от ваших параметров. Третья команда задаёт идентификатор вашего GPG-ключа для подписи:
[cas@cas ~]$ gpg --list-keys | grep -B 1 'Andrey Cherepanov' pub 1024D/A9EBF131 2007-03-13 uid Andrey Cherepanov (ALT Linux Team) <cas@altlinux.ru>
или
[cas@cas ~]$ gpg --list-secret-keys ------------------------------ sec 1024D/A9EBF131 2007-03-13 uid Andrey Cherepanov (ALT Linux Team) <cas@altlinux.ru>
Окружение RPM
Создайте файл ~/.rpmmacros следующего содержания (конечно, заменив ключ и имя мейнтейнера на свои):
%packager Andrey Cherepanov <cas@altlinux.org> %_gpg_name A424A3962331FDD2748BC8B34863C0F4A9EBF131
В %_gpg_name указывается отпечаток ключа (а не краткий идентификатор, как для Git). Получить его можно командой:
[cas@cas ~]$ LANG=C gpg --fingerprint A9EBF131 | grep 'fingerprint =' | tr -d ' ' | cut -d= -f2 A424A3962331FDD2748BC8B34863C0F4A9EBF131
Окружение Hasher
Для начала создайте под правами root двух служебных пользователей для сборочницы (среды сборки Hasher):
[cas@ham1 ~]$ su - Password: [root@ham1 ~]# hasher-useradd cas Adding user cas to group cas_a Adding user cas to group cas_b Adding user cas to group hashman
Вместо «cas» нужно указать существующего пользователя на машине, где будет развёрнута сборочная среда.
Далее для простейшей конфигурации Hasher потребуется создать каталог ~/.hasher со следующими файлами:
~/.hasher/config
USER=cas workdir="/tmp/.private/cas/" target=i586 packager="`rpm --eval %packager`" apt_config="$HOME/.hasher/apt.conf" mount=/dev/pts,/proc
Соответственно, USER должен быть такой же, как заведён в hasher-useradd, target — указывать на архитектуру собираемый пакетов.
Подготовка репозитория Git
Создание репозитория
Репозиторий Git создать очень просто. Для этого создадим каталог (имена пакетов лучше указывать в нижнем регистре, поэтому наш пакет для проекта будет называться kchildlock), перейдём в него и запустим git init:
mkdir kchildlock cd kchildlock git init .
Создание веток
Совсем необязательно, но удобно, когда оригинальный программный код расположен в отдельной ветке репозитория. Тогда код, в который вносятся изменения, файлы необходимые для сборки RPM пакета располагаются в своих, отдельных ветках. Если в этом нет нужды, продолжение этого раздела можно пропустить.
Например, можно сделать вот такие ветки:
- master - здесь будут находится служебные файлы, используемые при сборке RPM пакета: Spec файлы, файлы Gear (.gear/, и прочее). Программный код может быть, а может и не быть в этой ветке. По выбору собирающего пакет.
- upstream - оригинальный, авторский, распакованный программный код, как он был предоставлен. Этот код будет хранится в этой ветке неизменным.
- devel - ветка, в которую будет скопирован авторский код. Если потребуется вносить изменения в программу, то изменения будут внесены именно в этой ветке.
Создайте необходимые ветки и заготовки файлов (команды выполняются в каталоге с созданным ранее репозиторием):
mkdir .gear touch .gear/rules touch kchildlock.spec git add .gear/rules kchildlock.spec git commit -a -m "Initial." git branch upstream git branch devel
Можно проверить, что получилось:
git branch git status
GIT сообщает, что текущая(активная) ветка 'master' (помечена '*' в выводе первой команды), что в отслеживаемых файлах нет изменений (вторая команда, там же - тоже указано имя текущей ветки).
Написание .gear/rules
Забегая вперёд, создайте правило для Gear.
echo "tar.gz: targetTag:kchildlock" > .gear/rules
Здесь 'targetTag' - некое, пока ещё "волшебное", имя. Это имя будет символизировать какой код, из какой ветки Вы хотите собрать и упаковать в RPM. Есть рекомендации составлять это имя из версии программы и номера сборки. Например: 0.0.1-alt4. Т.е. 0.0.1 - версия программы, alt4 - четвёртая сборка этой версии для ALT Linux. Я здесь выбираю это имя равным 'targetTag'.
'kchildlock' - это имя каталога, в котором будет находиться программный код. Оно соответствует имени собираемого пакета. Код из этого каталога будет собран и упакован в пакеты.
Импорт исходного кода
Простой способ
Есть разные способы. Простейший: скопировать программный код в один из каталогов в репозитории. Для этого выполните:
git checkout upstream mkdir -p kchildlock
И любыми удобными средствами распакуйте, скопируйте исходный код программы в каталог 'kchildlock'. Когда код скопирован, выполните:
git add kchildlock git commit -a -m "Original source code is imported."
Импорт из src.rpm
Написание спека
В Spec файле потребуется указать группу, к которой нужно отнести собираемый пакет. Список групп в файле '/usr/lib/rpm/GROUPS'.
Поиск зависимостей
Поиск - занятие творческое. Панацеи нет. Сначала нужно посмотреть, что пишут авторы у себя на сайте, в файлах, приложенных к исходному коду. Это сформирует примерный список нужного.
Теперь можно использовать поиск в репозитории дистрибутива. Это команды:
apt-cache search искомое-сочетание1 искомое-сочетание2 apt-cache show имя-существующего-пакета
Найденные зависимости должны быть внесены в Spec файл.
После этого можно пытаться собрать пакет, переходить к следующим разделам этой статьи. Но! Часто бывает - не все зависимости были найдены сборщиком пакета. Тогда, позже надо будет вернуться к редактированию Spec файла. При сборке пакета, в отчётах о ошибках будут упоминаться имена конкретных недостающих файлов. Нужно искать пакеты в которых есть эти файлы. Решать какие из этих пакетов перечислить в Spec файле.
Один из способов поиска - творчески применять выше перечисленные утилиты apt-*. Один из более эффективных способов - смотреть в индексных файлах 'contents_index' репозитория. В этих файлах на отдельных строках приведено соответствие полного имени файла из пакета и имени этого пакета.
Пример расположения этих файлов:
repo-address/repo-name-architecture/base/contents_index /altair/ALT/Sisyphus/noarch/base/contents_index /altair/ALT/p6/noarch/base/contents_index
'repo-address', '/altair/ALT/*/' и т.п. это адреса репозитория, описанные в файле '/etc/***/apt.conf'. 'repo-name-architecture', 'noarch' - архитектура пакетов в репозитории. 'base' - имя каталога с искомым файлом.
Репозиториев, обычно, несколько. Индексных файлов будет несколько. Некоторые из файлов размером в сотни Мб.
Искать удобно так:
- сложить все файлы в один каталог под именами вроде contents_index_имя-архитектура-репозитория
- выполнять в этом каталоге команду:
grep -r искомая-часть-имени .
/* Есть заготовка скрипта для вытаскивания файлов. */
А иногда в дистрибутивах (в репозиториях) бывают доступны специальные, готовые к использованию утилиты для поиска соответствий короткого имени файла и имени пакета. Например, утилита 'apt-file'.
Если зависимость всё равно не находится, то далее можно разбирать скрипты конфигурации и т.п. Смотреть, что именно ищется конфигураторами кода, пытаться понять, что именно в своём дистрибутиве соответствует найденному в конфигураторах, прорабатывать это.
Возможно, что проще, иногда правильнее, собрать из оригинального кода дополнительные, отдельные пакеты с недостающими зависимостями. Но не всегда. Панацеи нет.
Есть и аварийный выход: взять зависимость в виде готового RPM пакета из другого дистрибутива. Например, скопировать из Fedora-Project и т.п. Возможно взять исходный код нужной версии собираемого пакета (*.src.rpm файлы) неавторский, а проработанный кем-то для Fedora-Project. И собирать уже его.
Секция инсталляции
При использовании утилиты 'install' можно не указывать конечного владельца и группу для инсталлируемого файла. Т.е. вместо
install -m755 -o root -g root targetFile %{buildroot}%{_bindir}
может быть использовано
install -m755 targetFile %{buildroot}%{_bindir}
О макросах
Если нужно узнать какие макросы есть в системе, можно заглянуть в файлы:
/etc/skel/.rpmmacros /etc/skel.ru_RU.CP1251/.rpmmacros /etc/skel.ru_RU.KOI8-R/.rpmmacros /home/${USER}/.rpmmacros /usr/lib/rpm/* /etc/rpm/*
Во что разворачивается макрос '%make_install' можно увидеть так:
rpm --eval %make_install
Система сборки пакета раскрывает макросы в Spec файле, даже если они находятся внутри комментария. Если нужно "выключить" макрос, то делается это аналогично выключению спец.символов в других системах - удвоением, повторением спец.знака '%':
# экранированный макрос %%configure
Конкретный пример Spec файла
/* Может быть на примере "Hello world.", вместо 'kchildlock' ???? */
Сборка в Hasher
В процессе сборки пакета, на диске будет существовать два важных, но разных каталога. 1) - каталог с GIT репозиторием, 2) - каталог с песочницей Hasher, в которой будут работать утилиты, собирающие пакет.
Немного ещё слов о GIT
GIT репозиторий хранит в себе историю изменения кода. Каждый коммит в репозиторий имеет свой идентификатор - SHA1 хэш, соответствует внесению каких-либо изменений. Можно сказать: каждый коммит соответствует какому-либо состоянию кода в той или иной ветке. Для сборки можно выбрать любое конкретное состояние кода, из любой ветки, указав сборочным утилитам нужный идентификатор коммита. Т.е. можно собирать пакет из кода какой-либо неактуальной и старой версии, всё ещё хранимой как история в репозитории. Или из кода хранимого в ветке, соседней по отношению к содержащей Spec файл.
Подготовка репозитория
Сборка будет осуществляться из ветки репозитория, содержащей Spec файл, Gear правила - т.е. из 'master'. Переключитесь на эту ветку:
git checkout master
Перед сборкой нужно определить какое именно сотояние кода, из истории в репозитории, нужно собирать - нужно выбрать какой-либо идентификатор коммита. Смотрите вывод комманды:
git log
Иногда в разборе истории помощь могут оказать разнообразные визуализаторы истории. Например, утилита gitk.
Например, пусть нужный коммит имеет SHA1 хеш равный '0123456789abcdef01234567890abcdef0123456'. Пометьте этот коммит тегом 'targetTag', обновите теги Gear, внесите сделанные изменения в репозиторий:
git tag -u A9EBF131 targetTag 0123456789abcdef01234567890abcdef0123456 gear-update-tag --all git commit -a -m "GIT and Gear tags updated."
Здесь идентификатор A9EBF131 надо заменить на идентификатор Вашего PGP ключа.
Свяжите текущее состояние ветки 'master' c выбранным для сборки состоянием кода (нужны имя ветки и хеш ранее выбранного коммита):
git merge -s ours upstream 0123456789abcdef01234567890abcdef0123456
Теперь, при запуске сборки, система будет собирать и упаковывать состояние кода, помеченное тегом 'targetTag'. См. ранее о правилах Gear.
Подготовка песочницы
Можно собирать пакет в каталоге-песочнице, создаваемом по умолчанию. Удобнее иметь несколько разных каталогов - несколько разных песочниц. Под разные архитектуры, под разные пакеты и разные версии...
Пускай путь к каталогу с песочницей будет '/pathToSandbox', собирать пакет требуется для x86_64 архитектуры. Структура каталогов, файлы в песочнице будут следующими:
/pathToSandbox |-hasher (файлы apt.conf, compile, priorities, sources.list) |---repo |-----SRPMS.hasher |-----x86_64 |-------RPMS.hasher |-tmp
Содержимое файлов см. ниже в приложении.
Если в каталоги вида '/pathToSandbox/repo/x86_64/RPMS.hasher' скопировать какие-либо RPM пакеты, сборочные утилиты могут использовать эти пакеты. Например, в этот каталог можно добавлять пакеты-зависимости отсутствующие в доступных репозиториях. Эти пакеты зависимости будут использованы при сборке (установлены внутри песочницы). Есть алгоритм выбора пакетов-зависимостей из репозиториев. Обычно (Всегда? А apt.*?) выбирается пакет с наибольшей версией.
Сборка
Конструирование песочницы занимает ощутимое временя. Для экономии времени можно использовать такую стратегию: сгенерировать песочницу один раз, при первой попытке сборки; в последующих попытках использовать уже готовую песочницу; GIT репозиторий не засорять пробными версиями Spec файла и т.п., используя параметр '--commit'.
Команды сборки выполняются в корневом каталоге GIT репозитория, активная ветка GIT репозитория - содержащая Spec файл и Gear правила.
Первичные команды для создания песочницы и сборки:
hsh --cleanup-only /pathToSandbox gear --verbose --commit --hasher -- hsh --verbose --lazy-cleanup --mountpoints=/proc --apt-config="/pathToSandbox/apt.conf" /pathToSandbox
Последующие попытки сборки выполняйте командой:
gear --verbose --commit --hasher -- hsh-rebuild --verbose --mountpoints=/proc /pathToSandbox
Полную очистку через 'hsh --cleanup-only' делать совершенно необязательно. Более точные команды см. в приложении - внизу страницы, "Файл compile для песочницы."
Если необходимо получать логи сборки в текстовых файлах, то используйте команду:
timestamp=$( date '+%Y-%m-%d-%H%M-%S' ) ; gear ... -- hsh ... 2>./error-${timestamp}.log 1>./build-${timestamp}.log ; unset timestamp
Многоточия надо заменить на необходимое, см. выше. (Неужели нет иного способа логгировать в файл или иную сущность, удобную для поиска в логе?)
Обратите внимание, что здесь прямо указан файл конфигурации apt.conf, несовпадающий с указанным в конфигурационном файле Hasher. Это может быть удобно, в случае многих песочниц.
При успешном окончании сборки будут выведены, в числе других, сообщения о том, куда и какие созданные RPM пакеты были скопированы.
Исследование результатов сборки
Если сборка неудачна, может потребоваться исследовать файлы и т.п. внутри песочницы. Для входа в песочницу используйте команды:
hsh-shell /pathToSandbox hsh-shell --rooter /pathToSandbox
Вторая команда позволяет получить root привилегии внутри песочницы.
Без дополнительных телодвижений нельзя одновременно войти в песочницу и осуществлять какие-то ещё операции Hasher. Однако, запущенное "параллельное" действие не прерывается, а ждёт окончания других операций.
Список инструментов внутри песочницы краток. Имена пакетов с недостающими необходимыми инструментами можно добавить как зависимости сборки в Spec файле - пакеты будут установлены в песочницу. Так же, можно использовать команду 'hsh-install' для доустановки пакетов вручную, находясь снаружи песочницы.
Для корректной работы некоторых программ в песочнице необходимо иметь внутри песочницы смонтированными некоторые файловые системы. Например, /proc для Java инструментов.
Сборочные утилиты производят ряд проверок файлов, получаемых при сборке, упаковываемых в пакет. При необходимости для исследований, некоторые проверки можно отключить. Одно из средств выключения - макросы в Spec файле:
%set_verify_elf_method no
Ещё - можно заглянуть в файлы '/usr/lib/rpm/noarch-linux/macros', '/usr/lib/rpm/brp.d/064-verify_elf.brp', '/usr/lib/rpm/verify-elf'.
Можно отключать проверки через аргументы в коммандной строке для Hasher. Например, вот такой аргумент '--no-sisyphus-check=bindir,subdirs,summary'.
Отправка в git.alt
Приложения
Файл apt.conf для песочницы
Dir::Etc::main "/dev/null"; Dir::Etc::parts "/var/empty"; Dir::Etc::sourcelist "/pathToSandbox/sources.list"; Dir::Etc::pkgpriorities "/pathToSandbox/priorities"; Dir::Etc::sourceparts "/var/empty"; APT::Cache-Limit "67108864";
Файл priorities для песочницы
Important: basesystem altlinux-release-sisyphus Required: apt
Файл sources.list для песочницы
rpm file:/altair/ALT/Sisyphus x86_64 classic rpm file:/altair/ALT/Sisyphus noarch classic
Файл compile для песочницы
Файл 'compile' является скриптом-обёрткой для запуска описанных в статье команд сборки (в т.ч. с указанием архитектуры и т.д.). В каталоге с GIT репозиторием можно создать символическую ссылку на такой файл. Можно создать разноимённые ссылки на файлы-обёртки в разных песочницах и запускать их по мере надобности, не покидая каталог репозитория, без необходимости работы с полными именами файла, из-за местоположения скрипта в другом каталоге.
#!/bin/bash # # Alex Vesev @ ALT Linux, 2012-10-05 # ## declare -r maintainerName="Alex Vesev" declare -r maintainerMail="*@*.*" declare -r dirSandBoxTop="/pathToSandbox" declare -r dirSandBoxHasher="${dirSandBoxTop}/hasher" declare -r optDirRepoHasher="--repo=\"${dirSandBoxTop}/repo/...\"" # XXX - применение не реализованно. function showDoc { cat "${0}" } [ "${#}" == 0 ] \ && showDoc \ && exit 1 cliArgument="${1}" cliOptionName="${cliArgument%%=*}" cliOptionName="${cliOptionName#--}" cliOptionValue="${cliArgument#*=}" case "${cliOptionName}" in shell|sh) hsh-shell --mountpoints="/proc" "${dirSandBoxHasher}" ;; build|bu) gear \ --verbose \ --commit \ --hasher \ -- x86_64 \ hsh \ --verbose \ --nprocs=2 \ --packager="${maintainerName} <${maintainerMail}>" \ --target=x86_64 \ --lazy-cleanup \ --mountpoints="/proc,/dev/pts,/sys" \ --apt-config="${dirSandBoxTop}/apt.conf" \ "${dirSandBoxHasher}" ;; rebuild|reb|rebu) gear \ --verbose \ --commit \ --hasher \ -- x86_64 \ hsh-rebuild \ --verbose \ --target=x86_64 \ --mountpoints="/proc,/dev/pts,/sys" \ "${dirSandBoxHasher}" ;; install|ins) shift 1 hsh-install "${dirSandBoxHasher}" "${@}" ;; clean-all) hsh --cleanup-only "${dirSandBoxHasher}" ;; esac
Ссылки
- Краткое руководство по сборке пакета
- Лекция Георгия Курячего "Демонстрация сборки пакета" (видео, ogv): [1]