Начиная с rosa2019.1, дистрибутив ROSA Fresh переходит с пакетных менеджеров RPM 5 и urpmi на RPM 4 и DNF. Эта статья описывает основные отличия для пользователей и сборщиков пакетов.

Содержание

Откуда куда переход

Более восьми лет в дистрибутивах ROSA Desktop использовался пакетный менеджер RPM5 - форк RPM4, созданный Джеффом Джонсоном. Долгое время RPM5 развивался гораздо активнее своего родителя, что и обсуловило его выбор для РОСЫ. Однако постепенно активность по разработке RPM5 угасла, а RPM4 наоборот - возродился и постепенно не только вобрал большинство интересных свойств RPM5, но и получил множество новых. В настоящее время сайт http://rpm5.org уже недоступен, а ROSA Fresh переходит обратно на RPM 4.

Было:

Стало:

Затронутые платформы: 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 вообще не тестируется, метаданные для него могут быть сломаны.

Причины для перехода

Общий план перехода

(возможны изменения, то, что еще не сделано, является приблизительным видением дальнейшей работы)

Изменения во флагах компилятора (CFLAGS, %optflags) по умолчанию

Части флагов не оказалось после перехода на rpm4, здесь описаны размышления, какие вернуть, а какие нет. Можно переделать.

- убран -fPIC: флаг был в cpu-os-macros.tar.gz, импортированном из Mandriva и не менявшимся, зачем он нужен в %optflags, я не понял, поэтому обратно в RPM4 не добавляю; пришлось в qt4 и qt5-qtbase добавить -fPIC вручную;

-fPIC возвращен; чтобы не было проблем с линковкой разделяемых библиотек, собранных с -fPIC, со статичными библиотеками, собранными без -fPIC, -fPIC возвращен в %optflags по умолчанию

Если необходимо отключить -fPIC для конкретного пакета, то можно сделать так:

 %global _fpic_cflags %{nil}

- убран -ffat-lto-objects: он был в rpm5/macros/mandriva.in, но не ясно, зачем тратить машинное время на компиляцию одновременно вариантов для LTO и нет, когда как LTO не используется в дистрибутиве, не понятно;

- убран -fno-delete-null-pointer-checks: он был тоже в rpm5/macros/mandriva.in, но зачем нужно изменять поведение gcc по умолчанию таким образом, не очень ясно; можно будет вернуть

UPD: этот флаг был вручную восстановлен в пакете webkit в соответствии с рекомендацией от 1С — проприетарной программы, использующей системный libwebkitgtk-3.0 (ALT#36998#c28). Возможно, его стоит вернуть глобально?

Полезные обсуждения по теме: 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

В 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
 O2
 Werror=format-security
 Wformat
 Wstrict-aliasing=2
 fomit-frame-pointer
 fPIC
 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	-
 frecord-gcc-switches		-
 fvar-tracking-assignments	-
 Wa,--compress-debug-sections	-
 				
 		Есть в RPM4	
 -				fomit-frame-pointer
 -				m64
 -				mtune=generic
 				
 		Общее		
 fstack-protector		fstack-protector-strong
 fPIC				fPIC
 gdwarf-4			gdwarf-4
 O2				O2
 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 по ссылке выше.

 Макрос     Значение в rpm4     Значение в rpm5
 %rpm4      1                   0
 %rpm5      0                   1
 %_rpm      4                   5
 %if %rpm4
 < вариант для rpm4 >
 %else
 < вариант для rpm5 >
 %endif

Если хочется заморочиться и сделать так, чтобы была ошибка сборки, если ни один из вариантов %if не сработал, то можно написать так:

 %if 0%{?rpm4}
 < вариант для rpm4 >
 %else
 %if 0%{?rpm5}
 < вариант для rpm5 >
 %else
 %{error:Error!}
 %endif
 %endif

Эта конструкция применит "< вариант для rpm4 >", если макрос %rpm4 задан и равен 1, "< вариант для rpm5 >", если макрос %rpm5 задан и равен 1, а если ни один из двух вариантов не подошел, то сборка упадет с ошибкой с текстом "Error!". Лучше избегать таких сложных конструкций!

По причине отсутствия пакетов python / python3 в базовой системе в BuildRequires не работают макросы %python* из этих пакетов. Однако пакет python3 подтягивается через cmake-rpm-generators.

Больше нет krb5-devel, поэтому в некоторых пакетах нужно прописать: "BuildRequires: pkgconfig(krb5" или "BuildRequires: pkgconfig(krb5-gssapi)", в некоторых пакетах с дурацкими сборочными скриптами, которые полагаются на автоматику и в которых нельзя в явном виде включить или выключить GSSAPI, например, в curl, рекомендуется добавить проверку по образцу:

 %check
 readelf -a %{buildroot}%{_libdir}/libcurl.so | grep NEEDED | grep -q libgssapi
 BUILDSTDERR: sh: /usr/bin/python: No such file or directory

В настоящий момент /usr/bin/python — это python2.

 %__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.

rpm4 не понимает значения %__requires_exclude(_from)/%__provides_exclude(_from) в кавычках. Кавычки нужно убрать.

Про варианты от RPM 4 читайте здесь.

Мы тщательно не изучали особенности раскрытия регулярных выражений в этих макросах-фильтрах, возможны нюансы, новые варианты сделаны эквивалентными старым для большинства типовых случаев.

Типовые замены макросов:

 %configure2_5x -> %configure
 %_sys_macros_dir -> %_rpmmacrodir
 %_rpmhome -> %_rpmconfigdir

Возможные, но нерекомендуемые замены:

 %make -> %make_build
 %makeinstall_std -> %make_install
 %setup_compile_flags -> %set_build_flags
 %ldflags -> %build_ldflags

Также появились %build_cflags (CFLAGS, флаги компилятора Си), %build_cxxflags (CXXFLAGS, флаги компилятора Cи++), %build_fflags (FFLAGS, флаги компилятора Фортран); в rpm5 они сделаны эквивалентными %optflags; %optflags продолжает существовать, как и раньше.

Макросы %make_* стали унифицированы с %ninja_*, %meson_* и др., т.е. build означает сборку, install — установку. Возможно изменение политики в отношение макросов.

 #%define xxx yyy

не будет работать, нужно заменить "#%define" на "#define"

 %__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 ему безразличен.

 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" и закоммитить, но для этого нужно составить список таких пакетов

 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 так делать не нужно.

 BUILDSTDERR: error: line 133: %package -n ipa-client47: package ipa-client47 already exists

Это логично, потому что %package, грубо говоря, используется для подпакетов, а пакет с именем %name уже и так автоматически задан. Пример исправления.

 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
 %files
 file.*
 %exclude file.php

Тогда в пакет попадут file.c и file.sh, а file.php не попадет. Но, если вы его вручную не удалите и не положите ни в один пакет, rpm5 выдаст ошибку о неупакованном файле, а rpm4 не выдаст и сам удалит этот файл. Изменение поведения rpm4 обсуждается здесь.

 # todo - use native %systemd_post

Была выдана ошибка:

 $ rpmspec --parse --trace kdebase4-workspace.spec
 <...>
   1>   %post^-n kdm
   1>   %systemd_post^
   2>     %{expand:%%{?__systemd_someargs_%#}}^
   3>       %#^
   3>       %{?__systemd_someargs_0}^
   4>         %{error:This macro requires some arguments}^
   1>   %{?_color_output}^{!?_color_output:auto}
   1>   %{!?_color_output:auto}^
 error: This macro requires some arguments

Решение: превратить "%systemd_post" в "%%systemd_post"

 require "find.pl";

была выставлена зависимость:

 Requires: perl(find.pl)

Но ни один пакет такое не провайдит. RPM 5 такую зависимость не выставлял. Решилось патчем, который заменил "require "find.pl";" на "use File::Find qw(find);".

 %define _python_bytecompile_build 0

В 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

 %if 0%{?rpm4}
 # rpm4 filetriggers
 %include %{SOURCE23}
 %else
 %if 0%{?rpm5}
 # rpm5 filetriggers
 %include %{SOURCE24}
 %else
 %{error:No file triggers have been included!}
 %endif
 %endif

где %{SOURCE23} и %{SOURCE24} — файлы, которые будут включены в спек, как если бы были его частью.