RPM Pakete erstellen

Anleitung, wie man einfache RPM-Pakete erstellen kann anhand zwei Beispielen ghostscript und DavMail.

Die Anleitung wurde unter AlmaLinux 9.1 erstellt, funktioniert aber auch mit anderen Distributionen. Dabei wurde sie etwas vereinfacht und deckt nicht jeden Sonderfall ab, funktioniert jedoch bei nicht zu komplizierten Paketen.

Voraussetzungen

Zum erstellen von RPM Paketen sind folgende Pakete notwendig:

dnf install rpmdevtools rpmlint rpm-sign git pinentry

Verwendet man Source-Code, der kompiliert werden muss (in diesem Beispiel ghostscript) wird natürlich auch noch der Compiler benötigt

dnf install gcc cpp

Die RPM-Erstellung sollte als Benutzer und nicht als root erfolgen und am einfachsten direkt in dessem Home-Verzeichnis.

Beispiel 1: ghostscript (aus Source)

Im Home-Verzeichnis des Benutzers wird mit den den Befehlen

rpmdev-setuptree
rpmdev-newspec rpmbuild/SPECS/ghostscript.spec

die benötigte Verzeichnisstruktur in einem Ordner rpmbuild erstellt. Ebenfalls wird ein Spec-File ghostcript.spec erstellt, welche als Basis dient. Der Dateiname kann dabei frei gewählt werden, sollte aber idealerweise er künftige Paketname sein.

Im Verzeichnis rpmbuild/SOURCES muss man nur ein tar.gz ablegen, das aus dem Paketnamen-Version besteht und in einen gleichnamigen Unterordner entpacken würde. Das Source-Paket von Ghostscript erfüllt diese Anforderungen bereits und die Datei ghostscript-10.03.0.tar.gz kann im SOURCES Verzeichnis abgelegt werden (muss nicht entpackt werden).

Nun muss man die Datei rpmbuild/SPECS/ghostscript.spec editieren:

Name: ghostscript
Version: 10.03.0
Release: 1%{?dist}
Summary: AGPL Ghostscript

License: GPL
URL: https://ghostscript.com/
Source0: ghostscript-10.03.0.tar.gz

%description
Sample Ghostscript 10.03.0 RPM Package

%prep
%autosetup

%build
%configure
%make_build

%install
rm -rf $RPM_BUILD_ROOT
%make_install

%files

Name und Version sollten der Einfachkeit halber den Dateinamen des vorher im SOURCES gepeichertem tar.gz Archiv entsprechen: Name=HalloWelt, Version=0.1 sucht also ein HalloWelt-0.1.tar.gz

Summary, License und URL können frei gewählt werden.

Source0 gibt den Dateinamen des .tar.gz Archivs an.

BuildRequires und Requires ist jeweils eine kommagetrennte Liste von Paketen, welche zum erstellen des RPMs bzw. für die Installation des RPMs benötigt werden. Hier sind keine Abhängigkeiten vorhanden, dann müssen die Zeilen auch gelöscht werden.

%description erlaubt eine etwas längere, auch mehrzeilige Paketbeschreibung.

%configure legt fest, dass vor dem make noch ein ./configure ausgeführt wird. Je nach Paket ist dies notwendig oder nicht.

Den Rest lassen wir (noch) auf Standardwerten.

Nun können wir mit

rpmbuild -ba -D 'debug_package %{nil}' rpmbuild/SPECS/ghostscript.spec

den Erstellvorgang starten. Dabei sollte man sich ausserhalb des rpmbuild-Ordners befinden. Dies dauert bei Ghoscript je nach Rechenleistung einige Minuten.

Am Ende zeigt das Script Dateien an, die im Spec-File nicht erwähnt wurden, das sind bei Ghostscript ziemlich viele:

Fehler beim Bauen des RPM:
 Installierte (aber nicht gepackte) Datei(en) gefunden:
 /usr/bin/dvipdf
 /usr/bin/eps2eps
 /usr/bin/gs
 /usr/bin/gsbj
 /usr/bin/gsdj
 /usr/bin/gsdj500
 /usr/bin/gslj
 /usr/bin/gslp
 /usr/bin/gsnd
 /usr/bin/lprsetup.sh
 /usr/bin/pdf2dsc
 /usr/bin/pdf2ps
 /usr/bin/pf2afm
 /usr/bin/pfbtopfa
 /usr/bin/pphs
 /usr/bin/printafm
 /usr/bin/ps2ascii
 /usr/bin/ps2epsi
 /usr/bin/ps2pdf
 /usr/bin/ps2pdf12
 /usr/bin/ps2pdf13
 /usr/bin/ps2pdf14
 /usr/bin/ps2pdfwr
 /usr/bin/ps2ps
 /usr/bin/ps2ps2
 /usr/bin/unix-lpr.sh
 /usr/share/doc/ghostscript/10.03.0/COPYING
 /usr/share/doc/ghostscript/10.03.0/GS9_Color_Management.pdf
 /usr/share/doc/ghostscript/10.03.0/Ghostscript.pdf
 /usr/share/doc/ghostscript/10.03.0/News.html
 /usr/share/ghostscript/10.03.0/lib/PDFA_def.ps
 /usr/share/ghostscript/10.03.0/lib/PDFX_def.ps
 ...
 /usr/share/ghostscript/10.03.0/lib/viewps2a.ps
 /usr/share/ghostscript/10.03.0/lib/winmaps.ps
 /usr/share/ghostscript/10.03.0/lib/zeroline.ps
 /usr/share/man/man1/dvipdf.1.gz
 /usr/share/man/man1/eps2eps.1.gz
 /usr/share/man/man1/gs.1.gz
 ...
 /usr/share/man/man1/ps2pdf14.1.gz
 /usr/share/man/man1/ps2pdfwr.1.gz
 /usr/share/man/man1/ps2ps.1.gz

Diese Liste kann man nun um Spec-File unter %files einfügen. Dabei darf man einzelne Dateien aber auch ganze Verzeichnisse angeben. Diese Dateien werden beim deinstallieren des RPM-Pakets wieder gelöscht, es sollte also nur dann ein Verzeichnis angegeben werden, wenn dieses bei Deinstallation auch komplett gelöscht werden darf. Ich gebe Verzeichnisse, die "ghostscript" enthalten als Verzeichnis an, die restlichen Dateien einzeln. Das ergibt im Spec-File

%files
/usr/bin/dvipdf
/usr/bin/eps2eps
/usr/bin/gs
/usr/bin/gsbj
/usr/bin/gsdj
/usr/bin/gsdj500
/usr/bin/gslj
/usr/bin/gslp
/usr/bin/gsnd
/usr/bin/lprsetup.sh
/usr/bin/pdf2dsc
/usr/bin/pdf2ps
/usr/bin/pf2afm
/usr/bin/pfbtopfa
/usr/bin/pphs
/usr/bin/printafm
/usr/bin/ps2ascii
/usr/bin/ps2epsi
/usr/bin/ps2pdf
/usr/bin/ps2pdf12
/usr/bin/ps2pdf13
/usr/bin/ps2pdf14
/usr/bin/ps2pdfwr
/usr/bin/ps2ps
/usr/bin/ps2ps2
/usr/bin/unix-lpr.sh
/usr/share/doc/ghostscript
/usr/share/ghostscript
/usr/share/man/man1/dvipdf.1.gz
/usr/share/man/man1/eps2eps.1.gz
/usr/share/man/man1/gs.1.gz
/usr/share/man/man1/gsbj.1.gz
/usr/share/man/man1/gsdj.1.gz
/usr/share/man/man1/gsdj500.1.gz
/usr/share/man/man1/gslj.1.gz
/usr/share/man/man1/gslp.1.gz
/usr/share/man/man1/gsnd.1.gz
/usr/share/man/man1/pdf2dsc.1.gz
/usr/share/man/man1/pdf2ps.1.gz
/usr/share/man/man1/pf2afm.1.gz
/usr/share/man/man1/pfbtopfa.1.gz
/usr/share/man/man1/printafm.1.gz
/usr/share/man/man1/ps2ascii.1.gz
/usr/share/man/man1/ps2epsi.1.gz
/usr/share/man/man1/ps2pdf.1.gz
/usr/share/man/man1/ps2pdf12.1.gz
/usr/share/man/man1/ps2pdf13.1.gz
/usr/share/man/man1/ps2pdf14.1.gz
/usr/share/man/man1/ps2pdfwr.1.gz
/usr/share/man/man1/ps2ps.1.gz

Danach kann der rpmbuild-Befehl nochmals genau identisch ausgeführt werden. Nun sollte der Vorgang erfolgreich sein:

Auf nicht gepackte Datei(en) wird geprüft: /usr/lib/rpm/check-files /home/devel/rpmbuild/BUILDROOT/ghostscript-10.03.0-1.el9.x86_64
Erstellt: /home/devel/rpmbuild/SRPMS/ghostscript-10.03.0-1.el9.src.rpm
Erstellt: /home/devel/rpmbuild/RPMS/x86_64/ghostscript-10.03.0-1.el9.x86_64.rpm
Ausführung(%clean): /bin/sh -e /var/tmp/rpm-tmp.0VyCmE
+ umask 022
+ cd /home/devel/rpmbuild/BUILD
+ cd ghostscript-10.03.0
+ /usr/bin/rm -rf /home/devel/rpmbuild/BUILDROOT/ghostscript-10.03.0-1.el9.x86_64
+ RPM_EC=0
++ jobs -p
+ exit 0

Das RPM-Paket kann nun normal mit rpm -i auf kompatiblen Systemen installiert werden. Die Ordnerstruktur bereit für rpmbuild inkl. fertigem RPM biete ich zu Demo-Zwecken zum Download an: rpmbuild-ghostscript10.tar.gz

Beispiel 2: DavMail (Binärdateien verwenden)

DavMail ermöglicht den Zugriff auf Exchange mittels IMAP/POP3/SMTP und wird hier als Beispiel verwendet. DavMail basiert auf Java.

Als Vorbereitung erstellen wir ein temporäres Verzeichnis davmail-6.0.1 und entzippen das ZIP-Archiv von der DavMail-Download-Seite. Das sollte aus den Dateien davmail und davmail.jar sowie dem Verzeichnis lib bestehen. Ebenfalls eine Beispiel-Konfiguration davmail.properties mit der Beispiel-Konfiguration der DavMail Webseite. Da die Software später nach /opt/davmail installiert werden soll erstellen wir auch noch das passende systemd-Startscript davmail.service mit folgendem Inhalt:

[Unit]
Description=DavMail server

[Service]
Type=simple
PermissionsStartOnly=true
ExecStartPre=/usr/bin/touch /var/log/davmail.log
ExecStart=/opt/davmail/davmail -server /opt/davmail/davmail.properties
SuccessExitStatus=143
PrivateTmp=yes

[Install]
WantedBy=multi-user.target

Damit haben wir die Binärdateien, eine Beispiel-Konfiguration und ein Start-Script. Davon erstellen wir mit

tar -zcvf davmail-6.0.1.tar.gz davmail-6.0.1

ein Archiv davmail-6.0.1.tar.gz, welches hier zu Demo-Zwecken auch zum Download angeboten wird. Damit sind die Vorbereitungen abgeschlossen.

Im Home-Verzeichnis des Benutzers wird mit den den Befehlen

rpmdev-setuptree
rpmdev-newspec rpmbuild/SPECS/davmail.spec

die benötigte Verzeichnisstruktur in einem Ordner rpmbuild erstellt. Ebenfalls wird ein Spec-File davmail.spec erstellt, welche als Basis dient. Der Dateiname kann dabei frei gewählt werden, sollte aber idealerweise er künftige Paketname sein.

Im Verzeichnis rpmbuild/SOURCES muss man nun das zuvor erstellte tar.gz Archiv ablegen, das aus dem Paketnamen-Version besteht und in einen gleichnamigen Unterordner entpacken würde (Archiv muss nicht entpackt werden).

Nun muss man die Datei rpmbuild/SPECS/davmail.spec editieren:

Name: davmail
Version: 6.0.1
Release: 1%{?dist}
Summary: DavMail Server
BuildArch: noarch

License: GPL
URL: https://davmail.sourceforge.net/
Source0: davmail-6.0.1.tar.gz

Requires: bash,java

%description
DavMail as RPM Build

%prep
%setup -q

%install
rm -rf $RPM_BUILD_ROOT
install -m 0755 -d $RPM_BUILD_ROOT/opt/davmail
install -m 0755 davmail $RPM_BUILD_ROOT/opt/davmail/davmail
install -m 0644 davmail.jar $RPM_BUILD_ROOT/opt/davmail/davmail.jar
install -m 0644 davmail.properties $RPM_BUILD_ROOT/opt/davmail/davmail.properties
install -m 0755 -d $RPM_BUILD_ROOT/opt/davmail/lib
install -m 0755 -d $RPM_BUILD_ROOT/usr/lib/systemd/system/
install -m 0644 davmail.service $RPM_BUILD_ROOT/usr/lib/systemd/system/davmail.service
install -m 0644 lib/activation-1.1.1.jar $RPM_BUILD_ROOT/opt/davmail/lib/activation-1.1.1.jar
install -m 0644 lib/commons-codec-1.11.jar $RPM_BUILD_ROOT/opt/davmail/lib/commons-codec-1.11.jar
install -m 0644 lib/commons-collections-3.1.jar $RPM_BUILD_ROOT/opt/davmail/lib/commons-collections-3.1.jar
install -m 0644 lib/commons-logging-1.0.4.jar $RPM_BUILD_ROOT/opt/davmail/lib/commons-logging-1.0.4.jar
install -m 0644 lib/htmlcleaner-2.21.jar $RPM_BUILD_ROOT/opt/davmail/lib/htmlcleaner-2.21.jar
install -m 0644 lib/httpclient-4.5.6.jar $RPM_BUILD_ROOT/opt/davmail/lib/httpclient-4.5.6.jar
install -m 0644 lib/httpcore-4.4.10.jar $RPM_BUILD_ROOT/opt/davmail/lib/httpcore-4.4.10.jar
install -m 0644 lib/jackrabbit-webdav-2.14.6.jar $RPM_BUILD_ROOT/opt/davmail/lib/jackrabbit-webdav-2.14.6.jar
install -m 0644 lib/jacocoant-0.8.5.jar $RPM_BUILD_ROOT/opt/davmail/lib/jacocoant-0.8.5.jar
install -m 0644 lib/javax.mail-1.5.6.jar $RPM_BUILD_ROOT/opt/davmail/lib/javax.mail-1.5.6.jar
install -m 0644 lib/jcharset-2.0.jar $RPM_BUILD_ROOT/opt/davmail/lib/jcharset-2.0.jar
install -m 0644 lib/jcifs-1.3.14.jar $RPM_BUILD_ROOT/opt/davmail/lib/jcifs-1.3.14.jar
install -m 0644 lib/jdom-1.0.jar $RPM_BUILD_ROOT/opt/davmail/lib/jdom-1.0.jar
install -m 0644 lib/jettison-1.4.0.jar $RPM_BUILD_ROOT/opt/davmail/lib/jettison-1.4.0.jar
install -m 0644 lib/log4j-1.2.16.jar $RPM_BUILD_ROOT/opt/davmail/lib/log4j-1.2.16.jar
install -m 0644 lib/slf4j-api-1.7.25.jar $RPM_BUILD_ROOT/opt/davmail/lib/slf4j-api-1.7.25.jar
install -m 0644 lib/slf4j-log4j12-1.7.25.jar $RPM_BUILD_ROOT/opt/davmail/lib/slf4j-log4j12-1.7.25.jar
install -m 0644 lib/sonarqube-ant-task-2.7.0.1612.jar $RPM_BUILD_ROOT/opt/davmail/lib/sonarqube-ant-task-2.7.0.1612.jar
install -m 0644 lib/stax2-api-3.1.1.jar $RPM_BUILD_ROOT/opt/davmail/lib/stax2-api-3.1.1.jar
install -m 0644 lib/stax-api-1.0.1.jar $RPM_BUILD_ROOT/opt/davmail/lib/stax-api-1.0.1.jar
install -m 0644 lib/woodstox-core-6.2.0.jar $RPM_BUILD_ROOT/opt/davmail/lib/woodstox-core-6.2.0.jar

%post
/usr/bin/systemctl daemon-reload

%clean
rm -rf $RPM_BUILD_ROOT

%files
/opt/davmail
/usr/lib/systemd/system/davmail.service

Name und Version sollten der Einfachkeit halber den Dateinamen des vorher im SOURCES gepeichertem tar.gz Archiv entsprechen: Name=HalloWelt, Version=0.1 sucht also ein HalloWelt-0.1.tar.gz

Summary, License und URL können frei gewählt werden.

Source0 gibt den Dateinamen des .tar.gz Archivs an.

BuildRequires und Requires ist jeweils eine kommagetrennte Liste von Paketen, welche zum erstellen des RPMs bzw. für die Installation des RPMs benötigt werden. Das fertige RPM soll bash und java voraussetzen. Build-Abhängigkeiten haben wir keine, diese Zeile müssen wir löschen.

%description erlaubt eine etwas längere, auch mehrzeilige Paketbeschreibung.

Da wir nichts kompilieren möchten löschen wir %configure, %make_build und %make_install.

Unter %install legen wir fest, welche Datei aus dem Archiv mit welchen Rechten wohin kopiert werden soll. Wir kopieren alles nach /opt ausser die systemd Konfiguration, die wird nach /usr/lib/systemd/system/davmail.service kopiert.

Mit %post werden Befehle angegeben, die nach der Installation ausgeführt werden, in unserem Fall lesen wir die systemd-Konfiguration neu.

%files definiert Dateien und Verzeichnisse, die betroffen sind. Diese werden bei der Deinstallation des Paketes wieder entfernt. Verzeichnisse sollten nur dann angegeben werden, wenn diese auch komplett gelöscht werden dürfen!

Den Rest lassen wir auf Standardwerten.

Nun können wir mit

rpmbuild -ba -D 'debug_package %{nil}' rpmbuild/SPECS/davmail.spec

den Erstellvorgang starten. Da nur Dateien kopiert werden müssen sollte das sehr schnell gehen. Die Ausgabe zeigt, dass alles funktioniert hat und das fertige RPM erstellt wurde.

Auf nicht gepackte Datei(en) wird geprüft: /usr/lib/rpm/check-files /home/test/rpmbuild/BUILDROOT/davmail-6.0.1-1.el9.x86_64
Erstellt: /home/test/rpmbuild/SRPMS/davmail-6.0.1-1.el9.src.rpm
Erstellt: /home/test/rpmbuild/RPMS/noarch/davmail-6.0.1-1.el9.noarch.rpm
Ausführung(%clean): /bin/sh -e /var/tmp/rpm-tmp.4tFCih
+ umask 022
+ cd /home/test/rpmbuild/BUILD
+ cd davmail-6.0.1
+ rm -rf /home/test/rpmbuild/BUILDROOT/davmail-6.0.1-1.el9.x86_64
+ RPM_EC=0
++ jobs -p
+ exit 0

Das RPM-Paket kann nun normal mit rpm -i auf kompatiblen Systemen installiert werden und wird reklamieren, wenn Java als Abhängigkeit fehlt. Die Ordnerstruktur bereit für rpmbuild inkl. fertigem RPM biete ich zu Demo-Zwecken zum Download an: rpmbuild-davmail6.tar.gz

RPM Paket signieren

Optional können RPM-Pakete auch noch signiert werden. Dazu müssen wir zuerst einen Key generieren

gpg --gen-key

Hier muss man Name und E-Mail Adresse angeben und den Key dann mit einem Passwort schützen. Dies zeigt eine ID an, welche später auch jederzeit mit

gpg --list-keys

anzeigen.

/home/test/.gnupg/pubring.kbx
-----------------------------
pub rsa3072 2022-12-20 [SC] [verfällt: 2024-12-19]
 1BE4CF808C5D8085A0761A79620239C09C89683B
uid [ ultimativ ] Juerg Sommer <xxx@yyy.com>
sub rsa3072 2022-12-20 [E] [verfällt: 2024-12-19]

Diese ID müssen wird speichern

echo %_gpg_name 1BE4CF808C5D8085A0761A79620239C09C89683B >> .rpmmacros

Danach kann das RPM mit folgendem Befehl signiert werden:

rpm --addsign rpmbuild/RPMS/noarch/davmail-6.0.1-1.el9.noarch.rpm

Dies fragt nach dem zuvor angegebenen Passwort.