Более восьми лет в дистрибутивах ROSA Desktop использовался пакетный менеджер RPM5 - форк RPM4, созданный Джеффом Джонсоном. Долгое время RPM5 развивался гораздо активнее своего родителя, что и обсуловило его выбор для РОСЫ. Однако постепенно активность по разработке RPM5 угасла, а RPM4 наоборот - возродился и постепенно не только вобрал большинство интересных свойств RPM5, но и получил множество новых. В настоящее время сайт http://rpm5.org уже недоступен, а ROSA Fresh переходит обратно на RPM 4.
Было:
Стало:
Затронутые платформы: rosa2021.1 (в будущем релизы ROSA >= 12) и новее, в старых (rosa2012.1, rosa2012lts, rosa2014.1, rosa2016.1, rosa2019.0) пакетная система не меняется.
Про этот переход было рассказано на конференции OSDAY-2020, ознакомиться с выступлением и слайдами презентации можно здесь: https://nixtux.ru/1052
(возможны изменения, то, что еще не сделано, является приблизительным видением дальнейшей работы)
Части флагов не оказалось после перехода на 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
Скрипт 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} — файлы, которые будут включены в спек, как если бы были его частью.
Генератор: https://abf.io/import/order-rpm-generators
Патч RPM, добавляющий нужный для его работа функционал: https://github.com/rpm-software-management/rpm/pull/1257
Во все пакеты добавляет: "OrderWithRequires: setup filesystem basesystem-minimal" + systemd при наличии файлов
'/(usr/lib|lib|etc)/(systemd|sysusers.d|tmpfiles.d)/.*$'
и chkconfig при наличии файлов
'/etc/(rc\..*|init\.d)/.*$'.
OrderWithRequires делает что-то приблизительно эквивалентное Requires(pre) (или без pre?), но только если указанный пакет существует в транзакции иными путями.
Этот генератор позволяет выправить порядок установки пакетов в больших транзакциях типа сборки образа с 3,5к пакетов, где иначе часть пакетов с сервисами или конфигами systemd, systemd-sysusers, systemd-tmpfiles ставятся, когда сам systemd еще не существует, из-за чего образ или чрут получается корявым.