Heute kam ich mal in die Verlegenheit, ein RPM aus einem Binary-Paket zu „backen“. Tante Google bringt zwar viele Infos zum Vorschein, aber nicht jede passt auch wirklich zu meinem Problem. Mit etwas probieren und ein wenig Lektüre habe ich das nachstehende, reale SPEC-File erstellt. Ich bezieh mich hier auf openSUSE 11.3 und dem mitgelieferten RPM in Version 4.8.0.
#Konstanten
%define elela_version 1.0.11113
%define elela_release 0
#Specfile fuer EleLa
Summary: EleLa - Elektronik Lagerverwaltung
Name: EleLa
Version: %{elela_version}
Release: %{elela_release}
License: Freeware
Group: Office/Database
Source: EleLa-%{elela_version}.tar.bz2
Vendor: Markus Mueller
URL: http://www.mmvisual.de
Distribution: openSUSE 11.3
Packager: Udo Neist <udo.neist@singollo.de>
Prefix: /opt
Requires: kchmviewer libsqlite3-0
Obsoletes: %name < %version
ExclusiveArch: i586
ExclusiveOS: Linux
ExcludeArch: sparc x86_64 m68k alpha
%description
Management of electronic components. Possibility to store images, creation of cases, type differentiation,
order management, quantities, project management, parts lists, history functions, knowledge base, label printing.
Supports different database systems, it can be used simultaneously with multiple computers.
%description[de]
Verwaltung von elektronischen Bauteilen. Speichermöglichkeit von Bildern, Anlegen von Gehäuse, Typunterscheidung,
Bestellungverwaltung, Stückzahlen, Projektverwaltung, Stücklisten, Historienfunktion, Wissensdatenbank, Etikettendruck.
Unterstützt unterschiedliche Datenbank-Systeme, so kann es auch mit mehreren Rechnern gleichzeitig benutzt werden.
%install
rm -rf $RPM_BUILD_ROOT%prefix/
mkdir -p $RPM_BUILD_ROOT%prefix/
tar xfvB $RPM_BUILD_SOURCE/%sources -C $RPM_BUILD_ROOT%prefix/
mkdir -p %{buildroot}%{_datadir}/applications
cat > %{buildroot}%{_datadir}/applications/%{name}.desktop <<EOF
[Desktop Entry]
Name=EleLa
Name[de]=EleLa
Comment=Management of electronic components. Possibility to store images, creation of cases, type differentiation,
order management, quantities, project management, parts lists, history functions, knowledge base, label printing.
Supports different database systems, it can be used simultaneously with multiple computers.
Comment[de]=Verwaltung von elektronischen Bauteilen. Speichermöglichkeit von Bildern, Anlegen von Gehäuse, Typunterscheidung,
Bestellungverwaltung, Stückzahlen, Projektverwaltung, Stücklisten, Historienfunktion, Wissensdatenbank, Etikettendruck.
Unterstützt unterschiedliche Datenbank-Systeme, so kann es auch mit mehreren Rechnern gleichzeitig benutzt werden.
Exec=%{prefix}/EleLa/EleLa
Icon=%{prefix}/EleLa/elela.png
Terminal=false
Type=Application
Categories=Qt:KDE;Office;Database;
EOF
%clean
rm -rf $RPM_BUILD_ROOT
%pre
if [ -d /usr/lib ]; then
if [ ! -L /usr/lib/libsqlite3.so ]; then ln -sf /usr/lib/libsqlite3.so.0 /usr/lib/libsqlite3.so; fi
fi
if [ -d /usr/lib64 ]; then
if [ ! -L /usr/lib64/libsqlite3.so ]; then ln -sf /usr/lib64/libsqlite3.so.0 /usr/lib64/libsqlite3.so; fi
fi
%post
if [ ! -f %{prefix}/EleLa/Tables.txt ]; then
mv %{prefix}/EleLa/Tables.txt.default %{prefix}/EleLa/Tables.txt
fi
if [ ! -f %{prefix}/EleLa/EleLa.sq3 ]; then
mv %{prefix}/EleLa/EleLa_Elektronik.sq3.default %{prefix}/EleLa/EleLa.sq3
fi
if [ ! -f %{prefix}/EleLa/EleLa_Waren.sq3 ]; then
mv %{prefix}/EleLa/EleLa_Waren.sq3.default %{prefix}/EleLa/EleLa_Waren.sq3
fi
if [ ! -f %{prefix}/EleLa/EleLa.ini ]; then
mv %{prefix}/EleLa/EleLa.ini.default %{prefix}/EleLa/EleLa.ini
fi
rm -rf %{prefix}/EleLa/*.default
if [ ! -L /usr/local/bin/EleLa ]; then ln -sf %{prefix}/EleLa/EleLa /usr/local/bin/EleLa; fi
chmod 777 %{prefix}/EleLa
mkdir -p %{prefix}/EleLa/Log
chmod 777 %{prefix}/EleLa/Log
%preun
if [ "$1" = 0 ] ; then
if [ -x %{prefix}/EleLa/EleLa ]; then
%{prefix}/EleLa/EleLa -uninstall
fi
fi
%postun
if [ "$1" = 0 ] ; then
if [ ! -f %{prefix}/EleLa/EleLa ]; then
rm -rf %{prefix}/EleLa/Log
if [ -L /usr/local/bin/EleLa ]; then rm /usr/local/bin/EleLa; fi
fi
rmdir --ignore-fail-on-non-empty %{prefix}/EleLa
fi
%files
%defattr(-,root,root)
%doc %{prefix}/EleLa/ReadMe.txt
%attr(777,root,root) %{prefix}/EleLa/EleLa
%attr(666,root,root) %{prefix}/EleLa/EleLa.chm
%attr(666,root,root) %{prefix}/EleLa/EleLa.ini_Demo_MySQL
%attr(666,root,root) %{prefix}/EleLa/EleLa.ini_Demo_PostgreSQL
%attr(666,root,root) %{prefix}/EleLa/EleLa.ini_Demo_SQLite
%attr(666,root,root) %{prefix}/EleLa/elela_MySQL_Start.sql
%attr(666,root,root) %{prefix}/EleLa/elela_Postgres_Start.sql
%{prefix}/EleLa/Lang_DE_Waren.txt
%{prefix}/EleLa/Lang_EN.txt
%{prefix}/EleLa/lclstrconsts.de.po
%{prefix}/EleLa/elela.png
%{prefix}/EleLa/libsqlite3.so
/usr/share/applications/EleLa.desktop
%attr(666,root,root) %{prefix}/EleLa/EleLa.ini.default
%attr(666,root,root) %{prefix}/EleLa/EleLa_Elektronik.sq3.default
%attr(666,root,root) %{prefix}/EleLa/EleLa_Waren.sq3.default
%attr(666,root,root) %{prefix}/EleLa/Tables.txt.default
Das SPEC-File definiert in den ersten Zeilen ein paar Konstanten, die im weiteren Verlauf des Builds verwendet werden. Damit vermeidet man Fehler, die durch nicht korrigierte Zeilen nach einer Änderung übersehen wurden. Die Kopfzeilen Summary bis Prefix sind ja noch einigermassen selbsterklärend, auch %description kann man noch verstehen, aber für die Abschnitte %install, %clean, %post, %postun und %files bedarf es etwas Erklärung.
Der Block %install enthält alle notwendigen Befehle, um das Ziel zu installieren. Da es ein binär-only-Paket sein soll, ist der Block %build erst gar nicht definiert. Die Variable %prefix definiert einen Default für das Installationsverzeichnis. Dieser sollte mit der Option –prefix überschrieben werden können. Zuerst wird ein eventuell vorhandenes Verzeichnis unter $RPM_BUILD_ROOT%prefix gelöscht und dann neu angelegt. Darin wird dann das Archiv entpackt. Im Archiv müssen bereits alle Rechte richtig gesetzt werden.
Nach dem Build wird das Verzeichnis einfach wieder geleert.
Dieser Abschnitt enthält alle Befehle, die nach der Installation ausgeführt werden sollen. Entsprechend gibt es auch ein Abschnitt %pre, der vor der Installation ausgeführt wird.
Analog zu %post undn %pre gibt es auch einen Abschnitt zur Befehlsausführung vor oder nach der Deinstallation.
Hier wird einfach eine Auflistung aller im Archiv vorhandenen Dateien angehängt. Dabei ist zu beachten, das die absoluten Pfade angegeben werden. Mit der „Anweisung“ %doc werden eventuelle Dokumentationen in das entsprechende Paketverzeichnis unter /usr/share/doc/packages kopiert. Das Macro %attr definiert die Rechte (chmod) und den Besitzer/die Gruppe des Files.
Sollte das SPEC-File fertig erstellt worden sein, so reicht ein
rpmbuild -v -bb Foo.spec --target=i586
für das Bauen eines für i586 definierten RPMs. Man kann hier andere Architekturen angeben. Läuft der Build fehlerfrei ab, existiert im zur Architektur passenden RPMS-Unterverzeichnis das fertige RPM. Man sollte es probeweise installieren, um eventuell noch vorhandene Fehler zu finden.
Dazu brauchen wir einen GPG-Schlüssel. Sollte noch keiner vorhanden sein, so lässt sich ein neuer mittels
gpg --gen-key
erstellen. Wenn bereits einer oder mehrere vorhanden sein sollten, kann man mit
gpg -k
eine Liste aller verfügbaren Schlüssel ausgeben lassen. Da ich selbst mehrere Schlüssel besitze, suche ich mir einen passenden mittels
gpg -k "Udo Neist"
aus der Liste heraus. Damit der Schlüssel auch öffentlich überprüfbar ist, sendet man diesen an einen Keyserver, wobei optional ein Keyserver angegeben werden kann. Mit folgender Zeile sendet man den Schlüssel an den Standard-Keyserver:
gpg --send-keys 08335316
Den Schlüssel sollte man auch auf Gültigkeit prüfen:
gpg --check-sigs 08335316
Den öffentlich Teil des Schlüssels exportiere ich mit
gpg --export --armor 08335316 > gpg-pub-key
den ich dann als User root in den RPM-Schlüsselbund importiere:
rpmsign --import gpg-pub-key
Um jedoch die RPMs auch noch zu signieren, muss ich eine Datei .rpmmacros in meinem HOME-Verzeichnis erstellen.
%_signature gpg %_gpg_name Udo Neist (udo@singollo.de) <udo@singollo.de> %_gpg_home /home/udo/.gnupg
Erst damit kann man ein RPM korrekt signieren:
rpmbuild -v --sign -bb Foo.spec --target=i586
Man wird nach dem Passwort für den Schlüssel gefragt, bevor ein signiertes Paket gebaut werden kann.