Springe zum Hauptinhalt

RPM

Paketinterna

Quellen und Patches

Alle zu eine Paket gehörenden Quellen (TAR-Archive, Scripte, Icons, Konfigurationsfiles, ...) müssen im Verzeichnis SOURCE des Build-Repositorys abgelegt werden.
Zusätzliche Files wie Skripte, Logos, usw können mit dem install -Kommando in die virtuelle Root installiert werden.

Source: quelle.tar.gz
Source1: script.sh
Source2: logo.png
Patch0: patch_abc.diff
Patch1: patch_xyz.diff

%prep
%setup -q
%patch0 -p1 -b .backup

%install
%{__mkdir_p} %{buildroot}/%{_bindir} \
             %{buildroot}/%{_datadir}/pixmaps
%{__install} -m 755 %{SOURCE1} %{buildroot}/%{_bindir}/
%{__install} -m 755 %{SOURCE2} %{buildroot}/%{_datadir}/pixmaps/

Tipp! Kann eine Quelle aus lizenzrechtlichen Gründen nicht im Source-RPM verteilt werden, wird das mit folgendem Tag erreicht:
NoSource: # wobei # für die Nummer der Quelle steht,

Patches

Ein Source-RPM verwendet immer die originalen Quellen. Veränderungen werden i.a. durch Patches eingearbeitet. Das Makro %patch# wendet den jeweiligen Patch mit der Nummer # an.
Die Option -p1 wird direkt an das patch-Kommando übergeben.
Die Option -b .backup erzeugt eine Backupkopie des/der Originalfiles mit der Endung .backup

Wie wird ein Patch erstellt ?

  • Originalverzeichnisstruktur myprog-0.2 aus den Quellen auspacken (rpmbuild -bp specfile.spec|source.srpm)und nach myprog-0.2.orig kopieren
  • Veränderungen im Verzeichnis myprog-0.2 vornehmen
  • in das Verzeichnis BUILD des Build-Repositorys wechseln
  • diff -Naur myprog-0.2.orig myprog-0.2 > ../SOURCE/mypatch.diff


Files

Alle in ein RPM zu integrierenden Files müssen in der %files -Sektion aufgeführt werden. Die Files werden in der BuildRoot gesucht. Für alle Files werden Zusatzinformationen wie Größe, Modus, Eigentümer, Gruppe, Prüfsumme usw. gespeichert.

Tipp! Für die Verzeichnisse sollten die vordefinierten Makros verwendet werden! Siehe dazu auch /usr/lib/rpm/macros

Statt die Files aufzuzählen kann auch eine Fileliste übergeben werden.

%install
find %{buildroot}/%{_datadir}/ -type f -name "*plugin.so" | %{__sed} "s|%{buildroot}||" > filelist.txt

%files -f filelist.txt

Tipp! Das Makro %find_lang erzeugt eine Fileliste aller sprachspezifischen Files (*.mo).

Anweisung Bedeutung
%doc README ChangeLog Dokumentationen werden relativ zum Quellpfad angegeben und nach /usr/share/doc/%{name}-%{version} installiert.
%defattr(-,root,root) Legt die Standard-Rechte und Eigentümer fest (im Beispiel nur Eigentümer und Gruppe)
%attr(755, root, root) %{_bindir}/mybin Legt Rechte und Eigentümer für dieses File fest
%config(noreplace) %{_sysconfdir}/my.conf Ein Konfigurationsfile, welches bei Upgrades nicht überschrieben wird
%ghost %{_datadir}/fonts/fonts.scale Das File fonts.scale wird nicht in das Paket eingepackt, gehört aber zum Paket. Beispielsweise wird fonts.scale mit dem Kommando ttmkfdir innerhalb der %post -Sektion erzeugt. In der BuildRoot muss das File existieren, bei der Deinstallation wird es mit entfernt.

Konfigurationsfiles

Konfigurationsfiles innerhalb von RPM-Paketen müssen dafür gekennzeichnet werden. Dadurch wird bei Updates das Überschreiben einer vorhanden Konfiguration vermieden. Ausserdem wird bei Änderung des zum Paket gehörenden Konfigfiles die Paketintegrität (Prüfsumme) nicht verletzt.

Source: quelle.tar.gz
Source1: sinnvoll.conf

%{__install} -m 644 %{SOURCE1} %{buildroot}/%{_sysconfdir}/sinnvoll.conf

%files
%config(noreplace) %{_sysconfdir}/sinnvoll.conf

Tipp! Als Konfigurationsdaten gekennzeichnete Files bleiben nach der Paketdeinstallation mit dem Suffix .rpmsave erhalten.

Desktop-Files (Startmenü)

Einträge im Startmenü werden für RedHat- und verwande Systeme über ein *.desktop -File im Verzeichnis /usr/share/applications erzeugt. Diese sind oberflächenübergreifend im Startmenü von GNOME und KDE sichtbar. Internationalisierung der Einträge kann für verschiedene Felder durch anhängen der Landeskennung erreicht werden (Name[de]=deutschsprach. Bezeichnung).

Die Installation des *.desktop -File erfolgt mit dem Werkzeug /usr/bin/desktop-file-install aus dem Paket desktop-file-utils (Achtung, Build-Abhängigkeit!).

Source1:     logo.png


%install
%{__mkdir_p} %{buildroot}/%{_datadir}/applications \
             %{buildroot}/%{_datadir}/pixmaps
%{__install} -m 644 %{SOURCE1} %{buildroot}/%{_datadir}/pixmaps/
cat > %{name}.desktop << EOF
[Desktop Entry]
Name=Mysoftware
Type=Application
Comment=Comment
Comment[de]=Kommentar
GenericName= generischer name
Exec=%{_bindir}/mybinary
Icon=logo.png
Terminal=0
EOF

desktop-file-install --vendor= \
                     --dir=%{buildroot}/%{_datadir}/applications \
                     --add-category=X-Red-Hat-Base \
                     --add-category=Application \
                     --add-category=Office \
                     %{name}.desktop 


%files
%{_datadir}/applications/%{name}.desktop  


Makros und Konditionen

RPM stellt für viele Funktionen innerhalb des Spec-Files Macros zur Verfügung. Die Auswertung ist z.B. mit if -Statements möglich. Die Makrodefinition sind zum großen Teil im /usr/lib/rpm/macros abgelegt und können mit dem Kommando rpmbuild --showrc angezeigt werden.

Makro Bedeutung
%{name} Paketname, entspricht dem Name: -Tag in der Header-Sektion
%{version} Paketversion, entspricht dem Version: -Tag in der Header-Sektion
%{release} Paketrelease, entspricht dem Release: -Tag in der Header-Sektion
%{buildroot} Verzeichnis, unter welchem eine "virtuelle" Root aufgespannt wird, um die Software zu installieren (entspricht dem BuildRoot: -Tag in der Header-Sektion)
%{SOURCE0} Name des ersten Quellfiles (absoluter Pfad)
%{_bindir} Pfad zum Binaryverzeichnis (/usr/bin/)
%{_libdir} Pfad zum Libraryverzeichnis (/usr/lib, /usr/lib64 für x86_64)
%configure entspricht einem ./configure (vgl. automake-Projekt) mit definierten Compilerflags und Parametern für --prefix, --libdir, usw.
%makeinstall entspricht einem make install mit definierten Parametern für --prefix, --libdir, usw.

Makros definieren und auswerten

%define logdir          /var/log         
%define _with_mylibrary 1
...
Source1: mydata.conf
%if %{_with_mylibrary}
BuildRequires: mylibrary-devel
%endif


%build
%if %{_with_mylibrary}
  %configure --logdir=%{logdir} --with-mylibrary
%else
  %configure --logdir=%{logdir}
%endif

%install
%{__install} -m 644 %{SOURCE1} %{buildroot}/%{_sysconfdir}/

%files
%{_bindir}/myprogram
%{_libdir}/mylib.so

Tipp! Macros sind case sensitive !

Tipp! Makros werden immer expandierd. Kommentare sollten folgende Form haben:
# %%define _with_mylibrary 1


Abhängigkeiten

automatische Abhängigkeiten

RPM erzeugt automatisch für die zum Paket gehörenden Binaries und Bibliotheken zwei Abhängigkeitslisten. In der Provides-Liste sind Komponenten aufgezählt, welche das Paket bereitstellt. Die Requires-Liste enthält für die Ausführung erforderliche Komponenten.

Die Provides-Liste wird automatisch aus allen in der %files -Sektion aufgeführten Bibliotheken erstellt.

Die Requires-Liste wird automatisch aus allen in der %files -Sektion aufgeführten Binaries mittels des Kommandos ldd erzeugt.

Die automatische Erzeugung der Abhängigkeitenliste kann mit Tags in der Header-Sektion deaktiviert werden.

Tag Bedeutung
AutoReq: no Automatisches erzeugen der Requires-Liste deaktivieren.
AutoProv: no Automatisches erzeugen der Provides-Liste deaktivieren.
AutoReqProv: no Automatisches erzeugen der Requires- und Provides-Liste deaktivieren.

Tipp! Die Erzeugung der automatischen Abhängigkeiten sollte nur in Ausnahmefälle deaktiviert werden. Z.B. bei der Paketierung binärer Quellen.

manuelle Abhängigkeiten

Zu den automatischen Abhängigkeiten können zusätzlich manuelle Abhängigkeiten im Specfile definiert werden. Dabei werden, im Gegensatz zu den automatischen Abhängigkeiten, zusätzliche Paketnamen referenziert.

Tag Bedeutung
Requires: mypaket, libmy > 0.1 Paket mypaket und Paket libmy > 0.1 werden von diesem Paket benötigt.
BuildRequires: libmy-devel > 0.1 Für den Buildprozess wird das Paket libmy-devel > 0.1 benötigt.
Provides: virt_pak_name Das Paket gibt sich zusätzlich mit dem virtuellen Paketnamen virt_pak_name aus.
Conflicts: mypaket Das Paket kollidiert mit dem Paket mypaket.

Tipp! Der Provides -Tag wird i.a. zum Erzeugen virtueller Paketnamen benutzt. Beispielsweise benötigt eine Java-Anwendung zum ausführen eine <nopJava-Laufzeitumgebung. Da es verschiedene Java-Umgebungen gibt, wird ein virtuelles Paket namens java angefordert, welches die Java-Laufzeitumgebungen bereitstellen.


Subpakete

Unter Subpaketen versteht man die Erzeugung mehrere RPMs aus einem Source-RPM bzw. Spec-File. Eine typische Anwendung von Subpaketen ist z.B. die Aufteilung eines Softwarepaketes in alle notwendigen Teile für das lauffähige Programme und ein Entwicklerpaket, welches nur die Headerfiles und Objekte für die Softwareentwicklung enthält.

Ein Subpaket wird mit dem Tag %package subpaketname definiert. Aus dem Paketnamen und dem Subpaketnamen ergibt sich der Name desSubpaketes %{name}-subpaketname. Alternativ kann auch ein Name ohne Zusammenhang zum Paketname vergeben werden %package -n subpaketname.

Der Buildprozess erzeugt zunächst alle Files. Die Unterscheidung zwischen Paket und Subpaket wird in den Skripten und im %files -Tag durch anhängen des Subpaketnamen erreicht.

Summary:        A library for decoding MPEG-1 and MPEG-2 video streams.
Name:           libmpeg2
Version:        0.4.0b
Release:        2
License:        GPL
Group:          System Environment/Libraries
Packager:       Marcin Garski <mgarski@post.pl>
URL:            http://libmpeg2.sourceforge.net/
Source0:        http://libmpeg2.sourceforge.net/files/%{archiname}-%{version}.tar.gz
BuildRoot:      %{_tmppath}/%{name}-%{version}
BuildRequires:  libXv-devel, pkgconfig, SDL-devel

%description
libmpeg2 is a free library for decoding MPEG-1 and MPEG-2 video streams.
It's main goals are standards conformance, speed, portability, and reuseability.
The package also includes mpeg2dec, a small test program for libmpeg2.

%package devel
Summary:        Development files for %{name}.
Group:          Development/Libraries
Requires:       %{name} = %{version}-%{release}, pkgconfig

%description devel
This package contains the libraries, include files and other resources
needed to develop applications using %{name}.

...

%files
%defattr(-, root, root)
%doc AUTHORS ChangeLog CodingStyle COPYING NEWS README TODO
%{_bindir}/*
%{_libdir}/libmpeg2*.so*
%{_mandir}/man1/*.1.gz

%files devel
%defattr(-, root, root)
%doc doc/libmpeg2.txt doc/*.c
%{_includedir}/mpeg2dec
%{_libdir}/libmpeg2*.a
%{_libdir}/libmpeg2*.la
%{_libdir}/pkgconfig/libmpeg2*.pc

Eine Sonderform von Subpakete mit dem Namen <name>-debuginfo-<version>-<release> werden für alle RPMs (ausser noarch -Pakete) automatisch erzeugt. Die in den RPMs enthaltenen Binaries werden automatisch gestripped ((Debug)-Symbole entfernt) verpackt. Für Debugzwecke kann das debuginfo -Subpaket installiert werden.


Scripte

Für die Ausführung von Skripten bei der Paketinstallation sind verschiedene Sektion vorgesehen. Dabei kann die Syntax von bash -Skripten genutzt werden. Eine typische Anwendung ist das Ausführen von /sbin/ldconfig nach der Installation/Deinstallation von Bibliotheken.

%post
/sbin/ldconfig

%postun
/sbin/ldconfig
if [ $1 -eq 0 ]; then
  %{__rm} -f somthing/else
fi

Skript Ausführungszeitpunkt
%pre vor der Installation eines Paketes
%post nach der Installation eines Paketes
%preun vor der Deinstallation eines Paketes
%postun nach der Deinstallation eines Paketes

Warnung! (Syntax) Fehler in Skripten führen zu Fehlern bei Paketinstallation, Update und Deinstallation!

Allen Scripts wird ein numerisches Argument übergeben, welches die aktuelle RPM-Aktion repräsentiert:

Aktion Skripts und Argumente
Deinstallation %preun 0, %postun 0
Installation %pre 1, %post 1
Update %pre 2, %post 2, %preun 1, %postun 1

Warnung! Beachte Skriptreihenfolge beim Update von Paketen!

  1. %pre Paket n
  2. files Paket n
  3. %post Paket n
  4. %preun Paket n-1
  5. %postun Paket n-1

Triggerskripte

Ist eine Aktion in Abhängigkeit von der Installation/Upgrade eines anderen Paketes erforderlich, kommen Triggerskripte zum Einsatz. Beispielsweise kann dadurch die Installation von Plugins organisiert werden.

%triggerin -- paketname
ln -sf %{_bindir}/%{name} %{_datadir}/software/plugins/

%triggerun -- paketname
if [ $1 -eq 0 ];then
  %{__rm} -f %{_datadir}/software/plugins/%{name}
fi 

Triggerskripten werden ebenfalls Argumente übergeben, welche die aktuelle RPM-Aktion repräsentiert.


Externe Steuerung des Paketbaues

Buildarchitektur

Die Buildarchitektur (noarch, i386, i686, x86_64) wird auf dem Buildhost bestimmt. Alternativ kann die Buildarchitektur dem Buildprozess übergeben werden oder in der Header-Sektion des Specfiles definiert werden.

Tipp! Anwendungsfälle für die expliziete Definition der Buildarchitektur sind z.B. (Shell) Skripte, Dokumentationen, Icons, Skins, Themes, ...

BuildArch: noarch

Beispiel
rpmbuild -bb --target "i386" Specfile|Source RPM

Übergabe von Parametern

Dem Buildprozess können Parameter übergeben werden, welche innerhalb des Specfiles ausgewertet werden können.

%{!?logdir: %define logdir /var/log}
%{?_with_mylibrary:BuildRequires: mylibrary-devel}

%build
%configure \
    %{?_with_mylibrary:--with-mylibrary } \
    --logdir=%{logdir}

Beispiel
rpmbuild -bb --define "_with_mylibrary 1" --define "logdir /tmp" [--nodeps] Specfile|Source RPM


Bau von Kernelmodule-Paketen

Problem:

  • Kernelmodule sind abhängig von installierter Kernelversion, -release und -architektur
  • mehrere installierte Kernel (Uniprozessor, SMP) erfordern auch mehrere installierte Kernelmoduln

Namensvergabe von Kernelmodule-Paketen

mehrere Ansätze:

  • Kernelversion in Paketnamen (!) integrieren kernel-module-openafs-2.6.9-42.0.3.EL.tucz.1-1.4.1-0rc10.SL.1.tucz
  • generische Paketname, Kernelversion in Paketrelease integieren openafs-kernel-1.4.2-2.6.18_1.2798.fc6_1.tuc

Tipp! Fedora Packaging Guideline empfiehlt: kmod-%{MODULE_NAME}

Abhängigkeiten

Grundsätzlich wird eine Abhängigkeit zu Kernelversion und -architektur definiert.

# define Name of Module
%define MODULE_NAME nvidia
# define release and arch of running kernel or the requested version
%define KERNEL_VERSION %(uname -r)
%define KERNEL_ARCH %(rpm -q --qf '%{arch}' kernel-%{KERNEL_VERSION})
Name:     kmod-%{MODULE_NAME}
Version:  1.0
Release:  9629.%(echo %{KERNEL_VERSION} | tr - _ )

Requires: kernel-%{KERNEL_ARCH} = %{KERNEL_VERSION}

Automatische (Kernel-) Updates (z.B. mittels yum) erfordern zusätzliche Provides: -Tags.
Ein einfaches Update-/Installhandling ist bereits in der yum-Klasse Depsolve::allowedMultipleInstalls implementiert. Mittels des yum-Plugin yum-fedorakmod ist ein komfortableres Updatehandling möglich.

Provides: kernel-modules = %{KERNEL_VERSION}
Provides: %{MODULE_NAME}-kmod = %{version}-%{release}
Provides: kmod-%{MODULE_NAME} = %{version}-%{release}

Skripte

Für die automatische Auflösung der "Symbole" müssen die Abhängigkeiten (modules.dep) aktualisiert werden. Dies wird per %post und %postun -Skript realisiert.

%post
/sbin/depmod -ae %{KERNEL_VERSION} > /dev/null || :

%postun
/sbin/depmod -ae %{KERNEL_VERSION} &> /dev/null || :

Tipp! Der Konstrukt /sbin/depmod || : verhindert, dass die Paketinstallation bei fehlgeschlagenem depmod abgebrochen wird.


Signieren von RPMs

Als zusätzlicher Integritätstest für ein RPM-Paket besteht die Möglichkeit des signierens. Durch Prüfen der Signatur gegen den öffentlichen Schlüssel der unterschreibenden Person/Einrichtung kann den Angaben im Paketheader vertraut werden.

Ein Schutz vor Mißbrauch z.B. der Skripts-Sektion ist damit nicht ausgeschlossen, aber durch den Import nur vertrauenswürdiger öffentlicher Schlüssel wird das Risiko reduziert.

Beispiel
# Erzeugen eines RSA-Key
$ gpg --gen-key
$ ls -al ~/.gnupg/
# Exportieren des Public Key (oeffentliche Bereitstellung)
$ gpg --export -a "URZ, TU-Chemnitz" > /tmp/pubkey
# Importieren des Public Key in die lokale RPM-Datenbank
$ sudo rpm --import /tmp/pubkey
# Konfiguration, zum signieren von RPMs erforderlich
$ echo -e "%_signature gpg\n%_gpg_path /home/anhe/.gnupg/\n%_gpg_bin /usr/bin/gpg \
           \n%_gpg_name URZ, TU-Chemnitz" >> ~/.rpmmacros[.base]
$ rpmbuild -bb --sign Specfile|Source RPM
$ rpm --checksig demo4-1.0-2.i386.rpm
demo4-1.0-2.i386.rpm: rsa sha1 (md5) pgp md5 OK

Kommando Bedeutung
rpm -qa "gpg-pubkey*"
Anzeigen aller importierten öffentlicher Schlüssel
rpm -qi gpg-pubkey-1ac70ce6-41bebeef
Anzeigen detaillierter Informationen eines öffentlicher Schlüssels
rpm --import PUBKEY
öffentlichen Schlüssel PUBKEY in die RPM-Datenbank importieren
rpm --checksig paket
Signaturen von paket prüfen
rpmbuild -bb --sign Specfile|Source RPM
Binäre Pakete erstellen und signieren
rpm --addsign|--resign paket
Paket paket signieren bzw. vorhandene Signatur überschreiben