How to package RPMs: a guide by someone who doesn't know what they're doing.
Find a file
2025-01-06 19:04:55 -06:00
polycat.spec minor improvements 2025-01-06 19:00:20 -06:00
README.md finish up initial version of the readme 2025-01-06 19:04:55 -06:00
update-version.sh minor improvements 2025-01-06 19:00:20 -06:00

How to package RPMs

A guide by someone who doesn't know what they're doing.

We'll be using polycat as an example, a fairly simple C++ program

Setup

First off, you're gonna want to install fedora-packager and rpmdevtools.

sudo dnf install fedora-packager rpmdevtools

Next, set up the directory tree for RPM packaging development.

rpmdev-setuptree

This will create ~/rpmbuild/, which will contain the following:

BUILD/  RPMS/  SOURCES/  SPECS/  SRPMS/

Then, to create a new .spec file, use rpmdev-newspec $FILENAME. As mentioned before, we'll be using polycat for our example.

rpmdev-newspec polycat.spec

Metadata

First off, there's the obvious metadata:

Name:           polycat
Version:        r93.0c836d5
Release:        %autorelease
Summary:        runcat module for polybar (or waybar)

License:        MIT
URL:            https://github.com/2IMT/polycat

%description
A runcat module for polybar (or waybar) written in C++

(note: License uses SPDX license list identifiers)

And the dependencies, also self-explanatory:

BuildRequires:  cmake g++ git tar
Requires:       glibc

Sources

Polycat's release could be considered out of date, as there hasn't been a commit in a bit over a year, so in my opinion packaging from the official release is not appropriate - it's also not what the official PKGBUILD for it on the AUR does. So instead, we'll be packaging it all, both polycat itself and its dependencies, via Git, rather than adding Source(s) to our spec file.

Additionally, Polycat uses Git submodules for dependencies, which %forgemeta doesn't support, as it doesn't clone recursively, and neither does Github's tarball, so we'll just clone it via Git directly.

%prep
git clone --recursive https://github.com/2IMT/polycat.git --depth 1 --shallow-submodules

Side note: You could use actual sources rather than git clone-ing it by using %forgemeta several times, or listing several Sources, but that's much more effort and is much harder to automate, for little benefit as far as I know.

Build

A few things here. First off, we'll start by declaring the %build section. Rather than just using CMake directly, rpmbuild has macros for it instead; pretty self-explanatory. However, cmake will instead output to ./redhat-linux-build/ if you don't specify where. Docs for all of this are here.

%build
cd ./polycat/
%cmake -DCMAKE_BUILD_TYPE=RELEASE
%cmake_build

Note that the different sections are run separately, the current directory is not preserved between them. So if we wanted to, say, apply some patches in %prep, then we'd still have to cd ./polycat again here

Install

As for the installation, you can use something like %make_install if applicable, but we'll just be installing Polycat manually.

%install
cd ./polycat/
mkdir -p %{buildroot}%{_bindir}
install -Dm755 ./redhat-linux-build/polycat %{buildroot}%{_bindir}/polycat
mkdir -p %{buildroot}%{datadir}/fonts/polycat/
install -Dm644 ./res/polycat.ttf %{buildroot}%{_datadir}/fonts/polycat/polycat.ttf

Again, because different sections are run separately, we have to cd into ./polycat/ again.

  • %{buildroot} is the root of the build's output directory - it contains the files that will be put in the rpm.
  • %{_bindir} defaults to /usr/bin

For more details on these macros, you can see this page.

Building the RPM

See rpmbuild's man page for details, but to build a binary package, we'll do this:

rpmbuild -bb polycat.spec

More metadata (%files)

We just finish this off by listing all the files this package provides. Not sure why rpmbuild doesn't just do this automatically, but if you don't list them, then rpmbuild will fail with Installed (but unpackaged) file(s).

%files
%{_bindir}/polycat
%{_datadir}/fonts/polycat/polycat.ttf

Resources