RPM-Pakete unter openSUSE bauen

20. Januar 2023

von Kevin Mandura

Inhaltsverzeichnis


Anhand eines einzelnen Bash-Skriptes möchte ich in dieser Anleitung grundlegend beschreiben, wie man unter der Linux-Distribution openSUSE ein RPM-Paket bauen kann, welches man hinterher unter kompatiblen Systemen mithilfe der RPM-Paketverwaltung ganz einfach installieren kann.

Dies zu wissen ist sehr praktisch, falls mal eine gewünschte Software nicht für das verwendete System in einer kompatiblen RPM-Paketform vorliegen sollte.

Bei meinem Einstieg in die RPM-Entwicklung unter openSUSE habe ich mich an die englischsprachige Anleitung bei der RedHat-Webseite gerichtet, da RedHat-basierende Distributionen und openSUSE beide das RPM-Paketformat nutzen und die RedHat-Dokumentationen im Allgemeinen gut aufbereitet und sehr hilfreich sind.

1. Software-Abhängigkeiten installieren

Um unter dem Betriebssystem openSUSE RPM-Pakete bauen zu können, führe die folgenden Befehle in einem Terminal aus, um die erforderliche Software aus den offiziellen openSUSE-Paketquellen zu installieren:

sudo zypper in -t pattern devel_rpm_build
$ sudo zypper in rpmdevtools rpmlint

2. RPM-Entwicklungsumgebung einrichten

Der gesamte Bauprozess von RPM-Paketen geschieht innerhalb eines übergeordneten Verzeichnisses namens rpmbuild. Dort wiederum gibt es eine standardisierte Struktur aus Unterverzeichnissen, in denen die unterschiedlichen Dateien, vom Quellcode bis hin zu den Binärpaketen, sehr übersichtlich einsortiert werden.

Administratorrechte werden zum Bauen von RPM-Paketen nicht benötigt. Computernutzer können in ihren Heimatverzeichnissen jeweils ihr eigenes rpmbuild-Verzeichnis verwalten und beliebig RPM-Pakete bauen.

Um eine RPM-Bauumgebung einzurichten, führe den folgenden Befehl als normaler Nutzer, den du alltäglich verwendest, aus:

rpmdev-setuptree

Hierdurch wird in deinem Heimatverzeichnis ein rpmbuild-Verzeichnis mit folgenden Unterverzeichnissen erzeugt:

rpmbuild
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

Grob gesagt, ist die RPM-Bauumgebung so aufgebaut:

3. Beispiel: Ein RPM-Paket bauen

Wie bereits am Anfang des Artikels angekündigt, werde ich den RPM-Bauprozess anhand eines einzelnen Bash-Skriptes zeigen.

Um genau zu sein, möchte ich ein Bash-Skript namens radio paketieren, bei dem es sich um einen sehr praktischen und effizienten Internetradio-Player handelt, den man wahlweise mit dmenu oder einem anderen Menü-Interface ganz bequem bedienen kann.

Zu finden gibt es die aktuellste Version dieses Skriptes in diesem Git-Repository:

Möchtest du dieses Skript herunterladen, um der Anleitung voll und ganz folgen zu können (empfohlen), nutze folgende Befehle in einem Terminal:

cd ~/Downloads
$ wget https://git.nevrlands.de/radio-sh/plain/radio

3.1. Quelldatei hinzufügen

Zuerst muss das Bash-Skript als Quelldatei in das vorhin erläuterte SOURCES -Verzeichnis kopiert werden.

Allerdings ist es empfehlenswert, das Bash-Skript davor noch zu komprimieren. Führe dazu folgende Schritte durch:

  1. Navigiere in das Verzeichnis, in dem sich das gewünschte Bash-Skript befindet.

  2. Erstelle ein neues Unterverzeichnis, in welches du die Skriptdatei anschließend hinein verschiebst. Verwende für den Verzeichnisnamen am besten den Namen der Skriptdatei (ohne Dateiendung), gefolgt von der Versionsnummer (z. B. 1.0.0) getrennt von einem Bindestrich.

    Dann komprimierst du das Verzeichnis.

    In meinem Fall gebe ich im Terminal ein:

    mkdir radio-2.0.9
    $ mv radio radio-2.0.9
    $ tar czf radio-2.0.9.tar.gz radio-2.0.9

    • radio-2.0.9.tar.gz ist der Dateiname der zu erstellenden, komprimierten Archivdatei. Üblicherweise gibt man hinter dem Skript-, bzw. Projektnamen noch die Versionsnummer des Ganzen an, sprich z. B. name-1.0.0.tar.gz.

    • radio ist in meinem Fall der Name der Shell-Skriptdatei. Durch das Weglassen der Dateiendung .sh kann das Skript nach der späteren Installation mit RPM ohne Weiteres mit dem Befehl radio ausgeführt werden, statt radio.sh.

Selbstverständlich kann man den Schritt der Komprimierung genauso gut per Rechtsklick in einem grafischen Dateimanager durchführen.

Die komprimierte Archivdatei verschiebst zu hinterher in das Verzeichnis: ~/rpmbuild/SOURCES/. In meinem Fall gebe ich ein:

mv radio-2.0.9.tar.gz ~/rpmbuild/SOURCES

3.2. Spezifikationsdatei erstellen

Als Nächstes erstellen wir eine RPM-Spezifikationsdatei, anhand dieser das RPM-Paket gebaut werden soll.

Um diese Datei nicht komplett von Hand verfassen zu müssen, nutzen wir die Vorteile des rpmdevtools -Pakets, um uns eine Basis-Vorlage zu generieren:

cd ~/rpmbuild/SPECS
$ rpmdev-newspec radio

Als Rückgabe des Befehls erhalten wir in etwa:

radio.spec created; type minimal, rpm version >= 1.0.

Die Verzeichnisstruktur sollte inzwischen ungefähr so aussehen:

rpmbuild
├── BUILD
├── RPMS
├── SOURCES
│   └── radio-2.0.9.tar.gz
├── SPECS
│   └── radio.spec
└── SRPMS

Öffne die Spezifikationsdatei nun in deinem bevorzugten Texteditor.

Im oberen Abschnitt der Datei definiert man unter anderem einen Projektnamen, eine Version, sowie eine Beschreibung, die verwendete Lizenz und vor allem auch die Quelldateien.

In meinem Beispiel trage ich folgende Informationen in den oberen Block ein:

Name:        radio
Version:     2.0.9
Release:     1%{?dist}
Summary:     conveniently play radiostreams
License:     GPL
BuildArch:   noarch
Source0:     %{name}-%{version}.tar.gz
URL:         https://git.nevrlands.de/radio-sh/plain/radio Requires:    bash mpv socat jq procps

Hinzugefügt habe ich das Schlüsselwort BuildArch: mit dem Wert noarch, da es sich einfach nur um ein Bash-Skript handelt, welches ja plattform-unabhängig funktioniert.

Unter Source0: – oder wahlweise auch Source: – geben wir das vorhin vorbereitete TAR-GZ-Archiv an. Aber: Um den Bauprozess für eventuell zukünftige Versionen zu vereinfachen, verwenden wir an geeigneten Stellen sogenannte Makros, sprich in diesem Fall %{name}-%{version}.tar.gz. Wie man sich schon denken kann, werden die beiden "Platzhalter" durch die oben spezifizierten Informationen unter "Name:" und "Version:" ersetzt.

Mit dem Schlüsselwort Requires: kann man gegebenenfalls Software-Pakete anhand des Paketnamens angeben, von denen dieses zu erstellende RPM-Paket abhängt.

Nach diesem Konfigurationsblock kann man unter %description einen Beschreibungstext für das RPM-Paket angeben, so zum Beispiel:

%description
The 'radio' bash script provides convenience features for radio streams.
Usage happens through the command line and various menus like dmenu or zenity.
Command Line arguments only yield results when mpv runs with an ipc-server,
which makes the script output-friendly for other external scripts without requiring a lot of string manipulation.
This script is aware of it's dependencies, whether they are files or executables. If a dependency is not met, the script aborts with a corresponding hint.

In der Basis-Vorlage enthalten ist außerdem eine %build-Sektion, welche wir für ein Bash-Skript gar nicht benötigen, da es hierbei nichts zum Kompilieren gibt:

%build
%configure
make %{?_smp_mflags}

Man könnte diesen %build-Block einfach aus der Datei löschen, allerdings sollte man stattdessen lediglich die zugehörigen Zeilen unter %build löschen, jedoch "%build" selbst stehen lassen.

Dazu gibt es nämlich folgenden Hinweis bezüglich der Best practice:

Even if some packages don't directly need it, section markers may be overridden in rpm's configuration to provide additional "under the hood" functionality, such as injection of automatic -debuginfo subpackages. Add the section, even if empty.

Als Nächstes müssen wir uns der %install-Sektion widmen.

Im Beispiel mit dem Bash-Skript, sollte diese nach der Bearbeitung so aussehen:

%install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/%{_bindir}
cp %{name} $RPM_BUILD_ROOT/%{_bindir}

Zuletzt müssen wir in der %files-Sektion genau angeben, welche Dateien an welche Stelle installiert werden. Da es ja in unserem Beispiel bekanntlich nur ein einziges Skript ist, geben wir folgendes an:

%files
%{_bindir}/%{name}

Sprich, das Shell-Skript wird hinterher unter /usr/bin installiert werden.

3.3. Spezifikationsdatei auf Fehler überprüfen lassen

Wenn man mit dem Editieren fertig ist, sollte man folgenden Befehl ausführen, um gegebenenfalls Fehler ausfindig zu machen:

rpmlint ~/rpmbuild/SPECS/radio.spec

Die Ausgabe sollte im Idealfall so aussehen:

0 packages and 1 specfiles checked; 0 errors, 0 warnings.

Andernfalls gibt eine oder mehrere Fehlermeldungen oder Warnhinweise gut verständlich Aufschluss darüber, was nicht in Ordnung ist.

3.4. Das RPM-Paket bauen

Folgender Befehl setzt den Bauprozess des RPM-Pakets in Gang:

rpmbuild -bb ~/rpmbuild/SPECS/radio.spec

Die Optionen -bb stehen für "build" und "binary" zur Erstellung eines Binärpaketes.
Für Quell-RPMs würde man stattdessen -bs für "build" "source" angeben.

Während des Bauprozesses werden sämtliche Schritte per Ausgabe im Terminal angezeigt, sodass man diesen genauestens nachverfolgen kann. In diesem Beispiel dauert der Buildprozess nicht mal eine Sekunde, weil es eben nur ein relativ überschaubares Bash-Skript ist.

Als letzte Zeile jedoch sollte folgendes erscheinen, was eine fehlerfreie Ausführung signalisiert:

+ exit 0

Andernfalls liest man sich die Ausgabe sorgfältig durch und erhält dadurch nähere Details, wo genau Probleme vorliegen. Typische Probleme waren bei mir zum Beispiel fehlerhafte Datei- und Pfadangaben in der Spezifikationsdatei, weswegen der Bauprozess mit einer entsprechenden Fehlermeldung "no such file or directory" scheiterte.

Wenn der Build also erfolgreich war, ist unser RPM-Paket im RPMS -Unterverzeichnis, und dort wiederum im Unterverzeichnis noarch (sprich keine bestimmte Plattform-Architektur) gelandet:

rpmbuild
├── BUILD
│   └── radio-2.0.9
│       └── radio
├── BUILDROOT
├── RPMS
│   └── noarch
│       └── radio-2.0.9-1.noarch.rpm
├── SOURCES
│   └── radio-2.0.9.tar.gz
├── SPECS
│   └── radio.spec
└── SRPMS

4. RPM-Paket installieren

Damit wäre es an der Zeit, das frisch gebaute RPM-Paket mal auszuprobieren.

Hierzu kannst du entweder YaST, bzw. den grafischen Dateimanager verwenden, indem du einen Rechtsklick auf das RPM-Paket machst, oder du nutzt folgenden Befehl:

sudo rpm -i ~/rpmbuild/RPMS/noarch/radio-2.0.9-1.noarch.rpm

Das installierte Bash-Skript kannst du dann in einer Shell über den Dateinamen direkt ausführen, in meinem Beispiel:

radio

Um das RPM-Paket zu deinstallieren, verwende:

sudo rpm -e radio


Ich hoffe, dieser Artikel hat dir dabei geholfen, ohne große Probleme ein grundlegendes Verständnis für das Bauen von RPM-Paketen zu gewinnen.

Natürlich bietet die RPM-Technologie noch zahlreiche Funktionsmerkmale, womit der Bauprozess sich weitaus komplexer gestalten kann, aber für den Anfang ist es bereits wirklich von Vorteil, wenn man gewöhnliche Software einfach selbstständig per RPM-Paket in die Softwareverwaltung integrieren kann, ohne dafür auf andere Personen angewiesen zu sein.

Die Online-Dokumentationen zum Thema RPM-Pakete bauen lassen dir beim Paketieren verschiedenster Software-Arten bestimmt keine Fragen offen.
Im Zweifel würde ich auch raten, z. B. bei den Git-Repositories anderer oder auch beim Open Build Service von openSUSE die unzähligen dort vorhandenen Spezifikationsdateien anzuschauen.

In diesem Sinne, viel Erfolg beim Paketieren!


Hat dir dieser Artikel gefallen?

Dieser Artikel wurde von Kevin Mandura verfasst.

Für Rückmeldungen hat der Autor Kontaktdaten angegeben.

E-Mail Kontakt
kontakt@kantinen-lieferservice.de

PayPal
Der Autor dieses Artikels nimmt Spenden via PayPal entgegen.
https://paypal.me/ktlsde

Monero
Der Autor dieses Artikels nimmt Spenden über die Kryptowährung Monero (XMR) entgegen.
Gebe als Empfänger-Adresse folgende an:
kantinen-lieferservice.de