Spec-файл состоит из preamble, %description, %prep, %build, %install, %check, scriptlets, %files, %changelog. В openSUSE changelog обычно ведётся в отдельном .changes; %changelog в spec остаётся последней секцией или не используется в привычном Fedora-стиле.

Минимальный skeleton:

Name:           foo
Version:        1.2.3
Release:        0
Summary:        Example daemon
License:        MIT
URL:            https://www.example.com/
Source0:        %{name}-%{version}.tar.zst
BuildRequires:  gcc
BuildRequires:  pkgconfig(systemd)
BuildRequires:  systemd-rpm-macros
%systemd_ordering

%description
Foo is an example daemon.

%prep
%autosetup -p1

%build
%make_build

%install
%make_install
install -D -m 0644 packaging/foo.service %{buildroot}%{_unitdir}/foo.service
install -D -m 0644 packaging/foo.tmpfiles %{buildroot}%{_tmpfilesdir}/foo.conf

%check
%make_build check

%pre
%service_add_pre foo.service

%post
%service_add_post foo.service
%tmpfiles_create foo.conf

%preun
%service_del_preun foo.service

%postun
%service_del_postun foo.service

%files
%license LICENSE
%doc README.md
%{_bindir}/foo
%{_unitdir}/foo.service
%{_tmpfilesdir}/foo.conf

Ключевые SUSE macros:

  • %{_libdir} - /usr/lib или /usr/lib64.
  • %{_libexecdir} - /usr/libexec в Tumbleweed после 2020-08-25 и в Leap 16; в Leap до 16.0 мог быть /usr/lib.
  • %{_unitdir} - systemd system units, обычно /usr/lib/systemd/system.
  • %{_tmpfilesdir} - /usr/lib/tmpfiles.d.
  • %{_sysusersdir} - /usr/lib/sysusers.d.
  • %suse_version, %is_opensuse, %sles_version - условные macros из project config.
  • %sle_version - встречается в старых Leap/SLE рецептах; для Leap 16/SLES 16 не полагайся на него без проверки. В OBS cross-distribution howto прямо указано, что SLES 16 currently doesn't use the sle_version macro.

Правильные conditionals:

%if 0%{?suse_version} == 1600 && 0%{?is_opensuse}
# openSUSE Leap 16.0
%endif

%if 0%{?suse_version} > 1600
# Tumbleweed или будущая openSUSE после Leap 16.0; проверяй Slowroll отдельно
%endif

Shared Library Packaging Policy: runtime package называется по SONAME, например libfoo1; -devel содержит headers, unversioned .so, pkgconfig/*.pc, CMake config; static libs только в -devel-static и только если есть обоснование.

%package -n libfoo1
Summary:        Shared library for foo

%post -n libfoo1 -p /sbin/ldconfig
%postun -n libfoo1 -p /sbin/ldconfig

%files -n libfoo1
%{_libdir}/libfoo.so.1*

%package devel
Summary:        Development files for foo
Requires:       libfoo1 = %{version}

%files devel
%{_includedir}/foo/
%{_libdir}/libfoo.so
%{_libdir}/pkgconfig/foo.pc

Scriptlets:

  • systemd: %service_add_pre, %service_add_post, %service_del_preun, %service_del_postun.
  • tmpfiles/sysusers: в актуальном systemd-rpm-macros %tmpfiles_create и %sysusers_create являются NOP из-за file triggers; если пользователь/группа нужны уже в %pre для ownership, используй %sysusers_create_package NAME SOURCE.
  • GConf - legacy; не добавляй новые GConf scriptlets в современный пакет без реальной зависимости.
  • info pages: современные file triggers часто делают старые %install_info ненужными; для старых веток проверяй Packaging_Conventions_RPM_Macros.
  • firewall: устанавливай firewalld service XML в правильный каталог, не правь runtime firewall state в %post.

Subpackages:

%package doc
Summary:        Documentation for foo
BuildArch:      noarch

%files doc
%doc docs/html

-debuginfo и -debugsource обычно генерируются автоматически; руками добавляй их только если понимаешь, почему автоматика не сработала.

Где искать дополнительно