Переход ROSA с RPM 5 на RPM 4
Содержание
Откуда куда переход
Более восьми лет в дистрибутивах ROSA Desktop использовался пакетный менеджер RPM5 - форк RPM4, созданный Джеффом Джонсоном. Долгое время RPM5 развивался гораздо активнее своего родителя, что и обсуловило его выбор для РОСЫ. Однако постепенно активность по разработке RPM5 угасла, а RPM4 наоборот - возродился и постепенно не только вобрал большинство интересных свойств RPM5, но и получил множество новых. В настоящее время сайт http://rpm5.org уже недоступен, а ROSA Fresh переходит обратно на RPM 4.
Было:
- низкоуровневая система управления пакетами RPM 5.4.10 (с более чем сотней патчей, специфичных для РОСЫ)
- высокоуровневый пакетный менеджер urpmi
- mock-urpm
Стало:
- низкоуровневая система управления пакетами RPM 4.15.1+
- высокоуровневый пакетный менеджер DNF
- исчез RPM-тег DistEpoch (не путать с Epoch), но появился DistTag
- вместо mock-urpm используется оригинальный mock
- наиболее часто используемые в командах urpmi и urpme функции преобразовываются в команды dnf (dnf-URPM)
- будет работающий PackageKit, на основе которого планируется графический "Магазин приложений"
Затронутые платформы: rosa2019.1 (в будущем релизы Rosa Desktop Fresh >= R12, Rosa Enterprise Desktop >= X5) и новее, в старых (rosa2012.1, rosa2012lts, rosa2014.1, rosa2016.1, rosa2019.0) пакетная система не меняется.
В данный момент для rosa2019.1 создаются одновременно метаданные и для urpmi (директория media_info), и для dnf (директория repodata). Метаданные urpmi обновляются при публикации пакетов, как положено, а метаданные dnf временно создаются через cron раз в 5 минут и пока только для main/release, main/updates, contrib/rlease contrib/updates, для non-free и restricted пока нет, но скоро появятся. Если вы парсите метаданные, то не стоит ориентироваться на метаданные от urpmi (media_info), потому что, как написано ниже, пока не ясно, останется он или нет. В rpm4 нет %__NVRA, нет distepoch, но есть disttag. Лучше всего парсить новые метаданные, как метаданные OpenMandriva Cooker/Fedora. В данный момент urpmi в rosa2019.1 вообще не тестируется, метаданные для него могут быть сломаны.
Причины для перехода
- ни RPM 5, ни urpmi более не разрабатываются, ROSA и PLD остались единственными их использующими дистрибутивами, причем PLD уже более года прорабатывает переход на rpm4; в мире Linux нецелесообразно пытаться малыми силами тащить такую важную инфраструктурную вещь, как пакетная система
- в RPM 5 в свое время были важные функции, которых не было в RPM 4, но теперь ситуация изменилась в обратную сторону
- апстрим RPM 4 в последнее время очень живой, RPM 4 активно развивается
- неудовлетворительное качество кода RPM 5 в РОСЕ, в котором так и осталось более сотни "костылей" со времен спешного перехода Mandriva на RPM 5 и много недоделанного функционала. Поддержка усложняется тем, что внутри кода RPM 5 содержатся копии многих сторонних проектов и отвечающий за что-то одно код размазан по огромному количеству файлов (например, см. коммит 5bf4d7: банально идентификаторы алгоритмов хеширования пришлось добавить в большое количество файлов)
- urpmi, конечно, немного жалко, но желающих в одиночку тянуть urpmi и perl-URPM не нашлось, а какого-либо критически важного функционала, отсутствующего в DNF, в urpmi нет
- нет качественных биндингов urpmi<->PackageKit, а их разработка и поддержка займет большое количество времени, которое можно потратить на другие вещи, и не очень целесообразна, поскольку есть много нюансов; если делать их только самим, то качество получится низким
Общий план перехода
(возможны изменения, то, что еще не сделано, является приблизительным видением дальнейшей работы)
- (СДЕЛАНО) собрать стек rpm4 с временными хаками, чтобы можно было использовать ранее собранные rpm5 пакеты *.rpm, например, игнорируя отсутствующую в стеке rpm4 %DISTEPOCH
- (СДЕЛАНО) обеспечить совместимость нового rpm4 с максимально возможным количеством старых макросов
- (СДЕЛАНО) автоматизированно внести массовые изменения в спеки (*.spec) так, чтобы они стали совместимы с RPM 4: меняются как места, которые строго необходимо заменить, так и те, где старый и продолжающий работать макрос меняется на его новый вариант
- (СДЕЛАНО) обеспечить совместимость старого rpm5 с измененными спеками, чтобы можно было из одного спека собирать пакеты и для rpm5 в платформах rosa2016.1 и rosa2019.0 и для rpm4 в платформе rosa2019.1
- (СДЕЛАНО) научить abf-console-client работать с RPM 4 (теперь апстрим общий с OpenMandriva — https://github.com/OpenMandrivaSoftware/abf-console-client, а старый клиент из ROSA на python2 — https://abf.io/soft/abf-console-client — остается только для RPM5)
- (В ПРОЦЕССЕ) провести массовую пересборку пакетов main и contrib, выявив и исправив типовые проблемы (например, уже запатчен find-lang.sh из rpm4)
- (В ПРОЦЕССЕ) ранее применявшимся в OpenMandriva скриптом автоматического обновления пакетов, где это возможно, обновить пакеты
- привести файловые триггеры RPM 5 и %trigger* к файловым триггерам RPM 4 (возможно, замапить новые %trigger* в старые для переиспользования спеков rpm4 в rpm5...)
- (СДЕЛАНО) обновить и починить gdb (gdb-add-index теперь используется в rpm, а gdb сейчас сломан из-за несовместимости с Python 3.8)
- (СДЕЛАНО, но не заапстримлено) портировать генератор зависимостей QML и желательно заапстримить его
- (СДЕАЛАНО) сделать генератор devel() или использовать от Mageia в составе rpm-openmandriva-setup; сделан свой
- починить не собирающиеся пакеты, возможно, снова обновив glibc и gcc
- либо отвязать drakxtools от perl-URPM (или перейти на manatools, как минимум настройку часов оттуда точно нужно взять, т.к. она умеет не только в ntpd, а еще и в chrony и systemd-timesyncd, а это важно), либо придется оставить urpmi в качестве существующего параллельно с DNF пакетного менедежера, как в Mageia
- если будет решено оставить urpmi и perl-URPM, то, во-первых, взять их версии из Mageia (они умеют работать c rpm4), во-вторых, перенести /usr/{sbin,bin}/{urpmi,urpme} куда-нибудь в /usr/lib/, а в (s)bin отставить dnf-URPM
- после обновления perl-URPM до версии из Mageia или его убирания обновить perl
- если получится избавиться от urpmi, наверняка стоит избавиться от префикса lib64 в названии пакетов, который существует из-за неумения urpmi отличать пакеты с одинаковым названием, но одинаковой архитектурой (но вопрос требует тщательного обдумывания, в т.ч. — не пострадает ли wine)
- переработать пакет rosa-repos: вынести main, contrib, non-free и т.д. в отдельные подпакеты
- собрать и обеспечить работу GUI для управления пакетами dnfdranoga
- сделать генерацию метаданных appstream из всего репозитория
- во все пакеты автоматически добавлять метаданные /usr/share/metainfo/*.xml, чтобы в графических "магазинах приложений" были все пакеты, а не только лишь те, в которых есть /usr/share/metainfo/*.xml; возможно, скрыть системные пакеты, имена которых начинаются на lib
- обновить весь стек GNOME и затем обеспечить работу gnome-software
- поскольку в drmdrake был GUI для управления репозиториями, а в dnfdranoga его нет, в пакеты rosa-repos-* добавить метаданные с описанием назначения этих репозиториев и с его переводом на русский язык; в магазинах приложений сделать отдельную категорию пакетов "Репозитории ROSA"; это позволит включать и отключать репозитории одной кнопкой "Установить"/"Удалить" пакет, также улучшит централизацию поставки конфигураций репозиториев
- собрать, обновить и обеспечить работу packagekit
- обеспечить работу оффлайн-обновлений через packagekit+systemd
- портировать хеши файлов по ГОСТ Р 34.11-2012 из rpm5 в rpm4 и желательно заапстримить (rpm4 уже переключен на libgcrypt по умолчанию)
- начать использовать security.ima и интегрировать подписывание в сборочницу, в т.ч. проработать вопрос с ГОСТ
- придумать, как существующие системы обновить до rosa2019.1 с rpm4 и задокументировать (будут проблемы с конвертированием БД rpm)
- осуществить полный переезд в /usr
- проработать нюансы, возникшие после смены %_libexecdir = %_libdir на %_libexecdir = /usr/libexec
- инсталлятор, скорее всего Anaconda, в которой есть в т.ч. режим, похожий на rsync в draklive-install, а также можно сделать выбор пакетов для установки, и есть поддержка kickstart-файлов
- сделать что-то с "бекендом" для urpmi в пакете system-config-printer, желательно выкинуть и использовать апстримную интеграцию с PackageKit; а сам system-config-printer отвязать от consolehelper и перейти на апстримную интеграцию с policykit, чтобы работала печать тестовых заданий с авторизацией по тикету Kerberos текущего пользователя
- ...
Изменения во флагах компилятора (CFLAGS, %optflags) по умолчанию
Части флагов не оказалось после перехода на rpm4, здесь описаны размышления, какие вернуть, а какие нет. Можно переделать.
- убран -fPIC: флаг был в cpu-os-macros.tar.gz, импортированном из Mandriva и не менявшимся, зачем он нужен в %optflags, я не понял, поэтому обратно в RPM4 не добавляю; пришлось в qt4 и qt5-qtbase добавить -fPIC вручную;
- убран -ffat-lto-objects: он был в rpm5/macros/mandriva.in, но не ясно, зачем тратить машинное время на компиляцию одновременно вариантов для LTO и нет, когда как LTO не используется в дистрибутиве, не понятно;
- убран -fno-delete-null-pointer-checks: он был тоже в rpm5/macros/mandriva.in, но зачем нужно изменять поведение gcc по умолчанию таким образом, не очень ясно; можно будет вернуть
Полезные обсуждения по теме: https://news.ycombinator.com/item?id=17360316, https://github.com/RIOT-OS/RIOT/issues/12039
- убран -fvar-tracking-assignments: надобность сомнительная, кому нужно дебажить, может сам собрать ПО, в т.ч. с -O0 вместо -O2, а еще не все компиляторы понимают этот флаг (clang вообще не понимает этот флаг, при его наличии приходится изобретать костыли вроде %clang_gcc_wrapper)
- убран -frecord-gcc-switches: надобность не очень понятна, а clang-у мешает
- было -fstack-protector в rpm5, стало -fstack-protector-strong в rpm4
- O2 превратился в -Os, сомнительное изменение
В rpm5:
rosa-2016 ~ # rpm --eval %optflags | sed -e 's, ,\n,g' | sed -e 's,^\-,,g' -e 's,^\-,,g' | sort -u ffat-lto-objects fno-delete-null-pointer-checks fPIC frecord-gcc-switches fstack-protector fvar-tracking-assignments gdwarf-4 O2 param=ssp-buffer-size=4 pipe Wa,--compress-debug-sections Werror=format-security Wformat Wp,-D_FORTIFY_SOURCE=2 Wstrict-aliasing=2
В rpm4:
bash-4.4# rpm --eval %optflags | sed -e 's, ,\n,g' | sed -e 's,^\-,,g' -e 's,^\-,,g' | sort -u D_FORTIFY_SOURCE=2 Os Werror=format-security Wformat Wstrict-aliasing=2 fomit-frame-pointer fstack-protector-strong gdwarf-4 m64 mtune=generic param=ssp-buffer-size=4 pipe
RPM5 RPM4 Есть в RPM5 ffat-lto-objects - fno-delete-null-pointer-checks - fPIC - frecord-gcc-switches - fvar-tracking-assignments - Wa,--compress-debug-sections - Есть в RPM4 - fomit-frame-pointer - m64 - mtune=generic Общее fstack-protector fstack-protector-strong gdwarf-4 gdwarf-4 O2 Os param=ssp-buffer-size=4 param=ssp-buffer-size=4 pipe pipe Werror=format-security Werror=format-security Wformat Wformat Wp,-D_FORTIFY_SOURCE=2 D_FORTIFY_SOURCE=2 Wstrict-aliasing=2 Wstrict-aliasing=2
Особенности перевода спеков на RPM 4
Скрипт rpm5-to-rpm4.sh, который автоматически вносит правки в спеки, здесь: https://gitlab.com/abf-mirror/abf-mirror-scripts
Если вы видите коммиты от "NixTux Commit Bot" с текстом: "bot: rpm5 -> rpm4 (N)", — где N — номер итерации прохода скрипта по всем пакетам в abf.io/import/, то это коммиты, сделанные этим скриптом. Каковы были изменения в скрипте между итерациями, можно посмотреть в git по ссылке выше.
- уменьшено количество пакетов в базовой сборочной системе, так, basesystem-build больше не зависит от initscripts, gpg и др. (см. коммиты), а из-за отсутствия initscripts больше нет, например, procps-ng с командой ps; минимизация сборочной системы — это скорее хорошо, чем плохо, т.к. ускоряет сборку, а мейнтейнер пакета будет вынужден лучше понимать, как происходит его сборка; при необходимости "потерянные" зависимости добавьте в BuildRequires вручную, пример."BuildRequires: /usr/bin/python2"
По причине отсутствия пакетов python / python3 в базовой системе в BuildRequires не работают макросы %python* из этих пакетов.
- из базовой сборочной системы убран /usr/bin/python, делайте "BuildRequires: /usr/bin/python" или "BuildRequires: /usr/bin/python2" или "BuildRequires: /usr/bin/python3" при необходимости; обратите внимание, что python3-devel, он же pkgconfig(python3) и аналогично python-devel/pkgconfig(python) не подтягивают /usr/bin/python(3). Характерная ошибка:
BUILDSTDERR: sh: /usr/bin/python: No such file or directory
В настоящий момент /usr/bin/python — это python2.
- Suggests и Requires(missingok) теперь Recommends: в RPM 5 были только Suggests и Requires(missingok) (а Suggests был алиасом Requires(missingok), а в RPM 4 есть и то, и то, но Recommends работает так, как работал Suggests, а Suggests используется для иных вещей, поэтому заменяем "Suggests:" на "Recommends:", а чтобы такие спеки продолжали работать в RPM 5, мы научили его понимать Suggests: теперь он считает и Suggests, и Recommends одинаково эквивалентными "Requires(missingok)"
- Фильтры для автоматического генератора зависимостей (requires) и провайдов (provides) поменялись следующим образом, ниже сначала вариант RPM 4 (новый), затем RPM 5 (старый):
%__requires_exclude -> %__noautoreq %__provides_exclude -> %__noautoprov %__requires_exclude_from -> %__noautoreqfiles %__provides_exclude_from -> %__noautoprovfiles
Нет возможности легко научить RPM 4 понимать %__noautoreq, %__noautoprov, %__noautoreqfiles и %__noautoprovfiles, но есть возможность легко научить RPM 5 понимать оба варианта, что мы и сделали. Теперь, если в спеке указаны одновременно старый макрос и эквивалентный ему новый макрос, например:
%define __noautoreq 'libGL.*' %global __requires_exclude 'libGL.*'
...то rpm5 будет брать только значение старого (__noautoreq) и игнорировать новый (__requires_exclude). Если же указан только новый (__requires_exclude), то будет браться его значение. В большинстве случаев достаточно использовать только новый вариант от RPM 4, т.е. только
%global __requires_exclude 'libGL.*'
...но, если вдруг понадобится задать разные правила для RPM 5 и RPM 4, то укажите оба варианта, тогда RPM 5 возьмет только свой прежний вариант, а RPM 4 только свой. Обратите внимание, что RPM 4 не понимает старые варианты от RPM 5, поэтому для RPM 4 обязательно указать __requires_exclude, а не __noautoreq. %global и %define здесь примерно одно и то же и для RPM 4, и для RPM 5, но документация от разработчиков RPM 4 рекомендует использовать %global, когда как в rpm5 более предпочтительно было %define.
Про варианты от RPM 4 читайте здесь.
Мы тщательно не изучали особенности раскрытия регулярных выражений в этих макросах-фильтрах, возможны нюансы, новые варианты сделаны эквивалентными старым для большинства типовых случаев.
- В пакете rpm-openmandriva-setup собраны макросы, которые существовали в RPM 5 и которых теперь нет в RPM 4, чтобы они продолжали работать в ROSA. Какие-то макросы просто скопированы, какие-то преобразовываются в их новые варианты. Также мы добавили некоторые широко распространенные новые макросы от rpm4 в rpm5, чтобы после их замены в спеках описанным выше скриптом спеки продолжали работать для rosa2016.1 и rosa2019.0 без изменений.
Типовые замены макросов:
%configure2_5x -> %configure %ldflags -> %build_ldflags %_sys_macros_dir -> %_rpmmacrodir %_rpmhome -> %_rpmconfigdir
Возможные, но нерекомендуемые замены:
%make -> %make_build %makeinstall_std -> %make_install %setup_compile_flags -> %set_build_flags
Также появились %build_cflags (CFLAGS, флаги компилятора Си), %build_cxxflags (CXXFLAGS, флаги компилятора Cи++), %build_fflags (FFLAGS, флаги компилятора Фортран); в rpm5 они сделаны эквивалентными %optflags; %optflags продолжает существовать, как и раньше.
Макросы %make_* стали унифицированы с %ninja_*, %meson_* и др., т.е. build означает сборку, install — установку. Возможно изменение политики в отношение макросов.
- rpm5 с описанными выше изменениями уже опубликован в rosa2019.0 и rosa2016.1
- Если нет иного выхода, то можно сделать if/else:
%if %{mdvver} >= 201910 < вариант для rpm4 > %else < вариант для rpm5 > %endif
- rpm4 не позволяет закомментировать %define:
#%define xxx yyy
не будет работать, нужно заменить "#%define" на "#define"
- в rpm4 не поддерживаются стадии BuildRequires, т.е. записи BuildRequires(check), BuildRequires(pre) заменяем на BuildRequires; потеря не велика, это использовалось очень редко и, как оказалось, во всем репозитории только одним из авторов этой статьи, при чем там, где без этого можно обойтись, просто для пущей красоты было
- %_libexecdir теперь не /usr/lib(64), а /usr/libexec
- в RPM 5 директории %_bindir, %_libdir и др. наследовали значение %_prefix, в rpm4 не наследуют, пример правок в пакете libressl (мы думаем над тем, как решить эту проблему, чтобы снова наследовалось значение %_prefix)
- в RPM 4 есть такой макрос:
%__pkgconfig_path ^((%{_libdir}|%{_datadir})/pkgconfig/.*\.pc|%{_bindir}/pkg-config)$
Если значение %_libdir переназначено, то файлы *.pc для создания Requires и Provides скриптом scripts/pkgconfigdeps.sh будут искаться, возможно, не там, где вы хотите
Пример решения (переназначим этот макрос, указав нужные пути):
%global __pkgconfig_path ^(%{_olibdir}/pkgconfig/.*\\.pc|%{_obindir}/pkg-config)$
В RPM 5 такого макроса нет, поэтому этот %global/%define ему безразличен.
- в RPM нельзя поставить %attr() на символическую ссылку, RPM 5 игнорировал такое, а RPM 4 выдает ошибку в явном виде, пример:
Explicit %attr() mode not applicable to symlink: /builddir/build/BUILDROOT/log4cpp-1.0-6.i386/usr/lib/liblog4cpp.so
Исправление — убрать лишний %attr
- в сборочнице теперь отключен доступ в сеть, часть пакетов не собирается с ошибкой вида:
BUILDSTDERR: error: Bad source: /builddir/build/SOURCES/mds-2.4.2.2.tar.gz: No such file or directory
В таких случаях нужно вручную или с помощью "abf put" закачать исходники пакета на ABF. Раз такие пакеты собирались ранее, значит в них достаточно автоматизированно сделать "abf put" и закоммитить, но для этого нужно составить список таких пакетов
- rpm5 съедал все содержимое папки с %doc, даже если туда положить что-то лишнее, а rpm4 требует явного указания всего содержимого папки /usr/share/doc/%name. Пример ошибки:
DEBUG: BUILDSTDERR: error: Installed (but unpackaged) file(s) found: DEBUG: BUILDSTDERR: /usr/share/doc/miau/examples/miaurc
При этом в пакете было:
%doc AUTHORS ChangeLog README TODO misc/miaurc
Файл examples/miaurc не прописан ни в %files, ни в %doc, а rpm5 игнорировал такую недоработку спека.
Другой пример:
# (cg) Copy the whole contrib dir as docs. It contains useful scripts. mkdir -p %{buildroot}%{_datadir}/doc/git-core cp -ar contrib %{buildroot}%{_datadir}/doc/git-core
Это рассчитано на поведение rpm5, для rpm4 так делать не нужно.
- rpm5 позволял написать: "%package -n %{name}", а rpm4 выдает ошибку:
BUILDSTDERR: error: line 133: %package -n ipa-client47: package ipa-client47 already exists
Это логично, потому что %package, грубо говоря, используется для подпакетов, а пакет с именем %name уже и так автоматически задан. Пример исправления.
- в RPM4 в макрос %configure входит:
find . -name config.guess -o -name config.sub | while read i ; do [ -f /usr/share/libtool/config/"$(basename "$i")" ] && /bin/rm -f "$i" && /bin/cp -fv /usr/share/libtool/config/"$(basename "$i")" "$i" ; done ; if [ -e configure.ac -a -e Makefile.am ]; then find . -name configure.ac |xargs dirname |while read D; do pushd $D; if grep -qE '(LT_INIT|LIBTOOL)' configure.ac >/dev/null; then libtoolize --force ; fi ; aclocal $((find . -name "*.m4" 2>/dev/null |grep -vE 'ac(local|include).m4' | xargs dirname) | grep -v '^.$' |sort |uniq |cut -d/ -f2- |while read R; do [ -e $R/configure.ac ] || echo -n "-I$R "; done) ; automake -a --foreign ; autoconf ; popd ; done ; fi ;
Этого не было и нет в %configure(2_5x) в RPM 5, но представляется полезным действием для актуализации сборочных скриптов тарболлов, что особенно важно при сборке на не-x86. Это может потребовать добавления новых BuildRequires, например, gettext-devel.
Если это пересоздание configure нужно отключить (например, при сборке пакетов libtool и autoconf, где такое действие вызывает как бы циклическую зависимость от самих себя), то:
%define _disable_rebuild_configure 1
- %exclude работает по-разному: в rpm, если в списке файлов (%files) есть %exclude, то он применяется, чтобы какой-то из файлов, попадающий в перечисленные файлы, не включать в этот список, например: есть файлы file.php, file.sh, file.c, а вы пишите:
%files file.* %exclude file.php
Тогда в пакет попадут file.c и file.sh, а file.php не попадет. Но, если вы его вручную не удалите и не положите ни в один пакет, rpm5 выдаст ошибку о неупакованном файле, а rpm4 не выдаст и сам удалит этот файл. Изменение поведения rpm4 обсуждается здесь.
- генератор зависимостей и провайдов Perl в RPM 4 "смотрит глубже". Например, в пакете autoconf2.1 на строку
require "find.pl";
была выставлена зависимость:
Requires: perl(find.pl)
Но ни один пакет такое не провайдит. RPM 5 такую зависимость не выставлял. Решилось патчем, который заменил "require "find.pl";" на "use File::Find qw(find);".
- байтовая компиляция в Python: в пакете python (python2), рядом с /etc/pythonrc.py, появились /etc/pythonrc.pyc и /etc/pythonrc.pyo, решилось так:
%define _python_bytecompile_build 0
Этот вопрос требует исследования.
- Перевод дополнительных макросов в пакетах на установку через %install_macro:
В RPM 4 и 5 используются разные места для размещения дополнительных макросов, но, что самое главное, отличаются имена файлов с макросами: в RPM 5 это *.macros, а в RPM 4 — macros.*. В связис этим был придуман макрос %install_macro, который создает универсальный метод установки макросов и в rpm4, и в rpm5. Макрос был добавлен в rpm4 и в rpm5. Пример:
%install_macro ninja %{SOURCE2}
устанавливает файл %{SOURCE2} в папку с макросами, на rpm4 называя файл macros.ninja, а на rpm5 — ninja.macros. В список файлов пакета (%files) пишем:
%{_rpmmacrodir}/*%{name}*
Под "*%{name}*" попадают и "%{name}.macros", и "macros.%{name}", что позволяет использовать один и тот же спек для сборки и на rpm4, и на rpm5, не делая if/else.
Примеры перевода пакетов на новую схему установки макросов: meson, ninja, python2, python3, qt5-macros, waf, firefox