# How to package RPMs A guide by someone who doesn't know what they're doing. We'll be using [polycat](https://github.com/2IMT/polycat) as an example, a fairly simple C++ program ## Setup First off, you're gonna want to install `fedora-packager` and `rpmdevtools`. ```sh sudo dnf install fedora-packager rpmdevtools ``` Next, set up the directory tree for RPM packaging development. ```sh rpmdev-setuptree ``` This will create `~/rpmbuild/`, which will contain the following: ```txt 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. ```sh rpmdev-newspec polycat.spec ``` ## Metadata First off, there's the obvious metadata: ```yml 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++ ``` <small>(note: License uses [SPDX license list](https://spdx.org/licenses/) identifiers)</small> And the dependencies, also self-explanatory: ```yml 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](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=polycat) 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. ```sh %prep git clone --recursive https://github.com/2IMT/polycat.git --depth 1 --shallow-submodules ``` --- <small>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.</small> ## 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](https://docs.fedoraproject.org/en-US/packaging-guidelines/CMake/). ```sh %build cd ./polycat/ %cmake -DCMAKE_BUILD_TYPE=RELEASE %cmake_build ``` <small>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</small> ## Install As for the installation, you can use something like `%make_install` if applicable, but we'll just be installing Polycat manually. ```sh %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 ``` <small>Again, because different sections are run separately, we have to `cd` into `./polycat/` again.</small> - `%{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](https://docs.fedoraproject.org/en-US/packaging-guidelines/RPMMacros/). ## Building the RPM See [rpmbuild's man page for details](https://www.man7.org/linux//man-pages/man8/rpmbuild.8.html), but to build a binary package, we'll do this: ```sh 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)`. ```sh %files %{_bindir}/polycat %{_datadir}/fonts/polycat/polycat.ttf ``` ## Resources - [Macros](https://docs.fedoraproject.org/en-US/packaging-guidelines/RPMMacros/) - Build systems - [CMake](https://docs.fedoraproject.org/en-US/packaging-guidelines/CMake/) - [Meson](https://docs.fedoraproject.org/en-US/packaging-guidelines/Meson/) - [%autosetup and %autopatch](https://rpm-software-management.github.io/rpm/manual/autosetup.html) (successors to [%setup and %patch](http://ftp.rpm.org/max-rpm/s1-rpm-inside-macros.html)) - [Using forges](https://docs.fedoraproject.org/en-US/packaging-guidelines/SourceURL/#_using_forges_hosted_revision_control)