Paketbau-Tutorial 2: GNU Hello

Dieses Tutorial demonstriert die Erstellung von RPM-Paketen anhand des Programms GNU Hello. Obwohl das Programm selbst recht einfach ist, enthält es auch viele weitere Komponenten eines Open-Source-Projekts: Konfigurations-, Bau- und Installationsumgebung, Dokumentation, Internationalisierung usw.

Dieses Tutorial ist der zweite Teil der Fedora-Paketierungsanleitung. Es folgt der gleichen grundlegenden Struktur wie Teil 1. Falls Sie Teil 1 noch nicht abgeschlossen haben, holen Sie dies bitte nach, bevor Sie mit diesem Tutorial fortfahren.

Die Schritte in diesem Abschnitt ähneln denen aus Abschnitt 1. GNU Hello weist jedoch mehr Eigenheiten auf als Banner, weshalb einige Problemumgehungen und benutzerdefinierte Schritte erforderlich sind. Da die Eigenheiten jedes Pakets einzigartig sind, sollten diese Beispiele lediglich die Art von Problemen verdeutlichen, die beim Paketieren auftreten können.

Paketbauwerkzeuge installieren

Zunächst müssen Sie die Paketbauwerkzeuge installieren.

Erstellen des Paketverzeichnisses

Für GNU Hello kann das Paket einfach hello genannt werden. Dies ist auch der Name des offiziellen GNU Hello-Pakets von Fedora.

$ mkdir hello && cd hello

In einer Spec-Datei

Erstellen Sie eine Datei namens hello.spec und fügen Sie die folgende minimale Spec-Datei ein. Diese enthält bereits BuildRequires-Tags für gcc und make, da dieses Thema bereits in Teil 1 behandelt wurde. Ebenso enthält der Abschnitt %files bereits die resultierende Binärdatei, die Handbuchseitendateien, die Dokumentation und die Lizenzdatei. Für GNU Hello sind all diese Dateien den entsprechenden Dateien in Banner sehr ähnlich und wurden daher bereits in Teil 1 behandelt.

Aus Gründen, die zu komplex sind, um sie in einem Tutorial zu erläutern, wird in manchen Situationen auch das Paket texinfo benötigt, weshalb dafür eine BuildRequires-Zeile hinzugefügt wird.

Name:           hello
Version:        2.10
Release:        %autorelease
Summary:        Produces a familiar, friendly greeting
License:        GPL-3.0-or-later
URL:            https://www.gnu.org/software/hello/
Source:         https://ftp.gnu.org/gnu/hello/hello-%{version}.tar.gz
BuildRequires:  gcc
BuildRequires:  make
BuildRequires:  texinfo

%description
The GNU Hello program produces a familiar, friendly greeting. Yes, this is
another implementation of the classic program that prints "Hello, world!" when
you run it.

%prep
%autosetup

%build
%configure
%make_build

%install
%make_install

%files
%{_bindir}/hello
%{_mandir}/man1/hello.1.*
%doc AUTHORS ChangeLog NEWS README THANKS TODO
%license COPYING

%changelog
%autochangelog

Herunterladen der Quellen

Laden Sie die Quellen herunter und überprüfen Sie, ob Sie sie nun haben:

$ spectool -g hello.spec
$ ls *.tar.gz
hello-2.10.tar.gz

Bau des Pakets

$ fedpkg --release f42 mockbuild

Dieser Befehl schlägt aufgrund nicht paketierter Dateien fehl.

Dateien installieren

Wie in Teil 1 gehen wir die Dateiliste nacheinander durch. Führen Sie nach jeder Änderung erneut fedpkg --release f42 mockbuild aus, um den Fortschritt zu sehen.

Texinfo-Seiten

Installed (but unpackaged) file(s) found:
/usr/share/info/dir
/usr/share/info/hello.info.gz

Dies sind Texinfo-Seiten. Texinfo ist ein Dokumentationssystem ähnlich wie Handbuchseiten (Manpages), jedoch deutlich weniger verbreitet. Texinfo-Seiten werden ähnlich wie Handbuchseiten verwaltet. Das Verzeichnis wird durch das Standardmakro {_infodir} definiert, so dass das Texinfo-Handbuch wie folgt hinzugefügt werden kann:

%files
⋮
%{_infodir}/hello.info.*

Die vom GNU Hello-Build-Skript generierte Datei dir indiziert alle texinfo-Seiten Ihres Systems. Da sich die installierten Seiten je nach System unterscheiden, kann die Datei nicht vorab erstellt und paketiert werden. Stattdessen muss sie bei der Paketinstallation erstellt und aktualisiert werden. Die Aktualisierung erfolgt automatisch durch RPM-Trigger im info-Binärpaket des texinfo-Quellpakets.

Um die Installation der Datei dir zu verhindern, entfernen Sie diese mit dem Befehl rm aus dem Verzeichnis buildroot am Ende des Abschnitts %install.

Das GNU Hello-Build-Skript generiert die Datei dir jedoch nur, wenn das Paket info während des Bauvorgangs installiert ist. Würde man die Datei einfach löschen, entstünde ein Fehler, wenn das hello-Paket auf einem System ohne das Paket info erstellt würde. Um beide Fälle abzudecken, löschen Sie die Datei, falls sie existiert:

%install
⋮
test -f %{buildroot}/%{_infodir}/dir && rm %{buildroot}/%{_infodir}/dir

Übersetzungen

Installed (but unpackaged) file(s) found:
/usr/share/locale/bg/LC_MESSAGES/hello.mo
/usr/share/locale/ca/LC_MESSAGES/hello.mo
/usr/share/locale/da/LC_MESSAGES/hello.mo
⋮

Da unser Programm Übersetzungen und Internationalisierung verwendet, stoßen wir auf viele nicht deklarierte i18n-Dateien. Die empfohlene Methode zur Deklaration dieser Dateien ist:

  1. Fügen Sie die erforderliche Bauabhängigkeit mit BuildRequires: gettext hinzu.

  2. Finden Sie die Dateinamen im %install-Schritt mit %find_lang %{name}.

  3. Installieren Sie die Dateien mit %files -f %{name}.lang.

Nach diesen Änderungen ist der Bauvorgang erfolgreich.

Tests ausführen

GNU Hello enthält, wie viele andere Projekte auch, eine automatisierte Testsuite in den Quellen. Diese Testsuite sollte nach Möglichkeit während des RPM-Bauvorgangs ausgeführt werden. Dadurch wird sichergestellt, dass ein lauffähiges Paket erstellt wird. Dies geschieht durch Hinzufügen des Aufrufs der Testsuite zum Abschnitt %check% der Spec-Datei, der in der Reihenfolge nach %install steht. Im Fall von GNU Hello:

%check
make check

Führen Sie erneut einen Mockbuild durch und überprüfen Sie die Ausgabe, um sicherzustellen, dass die Tests tatsächlich ausgeführt wurden. Die Ausgabe sollte etwa Folgendes enthalten:

============================================================================
Testsuite summary for GNU Hello 2.10
============================================================================
# TOTAL: 5
# PASS:  4
# SKIP:  1
# XFAIL: 0
# FAIL:  0
# XPASS: 0
# ERROR: 0
============================================================================

Automagisch korrigieren

Das Paket lässt sich nun erfolgreich bauen. Das bedeutet aber nicht, dass die .spec-Datei korrekt ist.

Auflisten aller Bauabhängigkeiten

Wenn Sie die Ausgabe eines Bauprozesses aufmerksam lesen, können Sie Zeilen entdecken, die den Befehl sed enthalten:

+ /usr/bin/make -O -j4 V=1 VERBOSE=1
rm -f lib/arg-nonnull.h-t lib/arg-nonnull.h && \
sed -n -e '/GL_ARG_NONNULL/,$p' \

Daher müssen Sie diese Zeile bei den anderen BuildRequires-Zeilen hinzufügen:

BuildRequires:  sed

Eine ähnliche Untersuchung des configure-Skripts in den nicht gepackten Quellen, das durch das %configure-Makro ausgeführt wird, zeigt, dass es sich um ein /bin/sh-Skript handelt:

$ head configure
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for GNU Hello 2.10.

Daher sollten Sie diese Abhängigkeit zu bash auch aufnehmen:

BuildRequires:  bash

Warum bash? Weil das Programm /bin/sh vom bash-Paket bereitgestellt wird:

$ rpm --queryformat '%{name}\n' --query --file /bin/sh
bash

Die Angabe aller verwendeten Abhängigkeiten trägt dazu bei, dass die .spec-Datei gegenüber Änderungen in der Bauumgebung robust ist. Würde beispielsweise das sed-Paket aus der Umgebung entfernt, könnte dieses GNU Hello-Paket nicht mehr erstellt werden.

Auflisten aller Bauoptionen

Das GNU Hello-Bauskript configure bietet zahlreiche Bauoptionen, mit denen optionale Funktionen aktiviert oder deaktiviert werden können. Ihre nicht standardmäßigen Formen können mit der Option --help aufgelistet werden:

$ ./configure --help
`configure' configures GNU Hello 2.10 to adapt to many kinds of systems.

Usage: ./configure [OPTION]... [VAR=VALUE]...
⋮
Optional Features:
  --disable-option-checking  ignore unrecognized --enable/--with options
  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
  --enable-silent-rules   less verbose build output (undo: "make V=1")
  --disable-silent-rules  verbose build output (undo: "make V=0")
  --enable-dependency-tracking
                          do not reject slow dependency extractors
  --disable-dependency-tracking
                          speeds up one-time build
  --disable-nls           do not use Native Language Support
  --disable-rpath         do not hardcode runtime library paths

Einige davon sind bereits in den Makros %configure und %make_build definiert. Die übrigen Optionen sollten, sofern sie für das zu erstellende Paket wichtig sind, explizit in der .spec-Datei aufgeführt werden, um plötzliche und unbemerkte Änderungen zu vermeiden. Dies kann beispielsweise der Fall sein, wenn eine neue Hello-Version die Standardeinstellungen ändert oder ein abhängiges Paket in der Bauumgebung erscheint oder daraus verschwindet.

Ändern Sie daher den Aufruf von %configure im Abschnitt %build wie folgt:

%configure --enable-nls --disable-rpath

Überprüfen des Ergebnisses mit rpmlint

Die Überprüfung mit fedpkg lint deckt ein Problem auf:

$ fedpkg --release f42 lint
hello.x86_64: W: file-not-utf8 /usr/share/doc/hello/THANKS

Um eine reine UTF-8-Installation zu gewährleisten, muss die Datei in %prep konvertiert werden. Dies kann mit dem Dienstprogramm iconv aus dem Paket glibc-common und dem Tool mv aus coreutils erfolgen:

BuildRequires:  coreutils
BuildRequires:  glibc-common
⋮
%prep
⋮
mv THANKS THANKS.old
iconv --from-code=ISO-8859-1 --to-code=UTF-8 --output=THANKS THANKS.old

Führen Sie fedpkg lint erneut aus und stellen Sie fest, dass die Ursache der Warnung behoben ist.

Eine vollständige hello.spec-Datei

Hier ist die endgültige Version von hello.spec:

Name:           hello
Version:        2.10
Release:        %autorelease
Summary:        Produces a familiar, friendly greeting

License:        GPL-3.0-or-later
URL:            https://ftp.gnu.org/gnu/%{name}
Source:         https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.gz

BuildRequires:  bash
BuildRequires:  coreutils
BuildRequires:  gcc
BuildRequires:  gettext
BuildRequires:  glibc-common
BuildRequires:  make
BuildRequires:  sed
BuildRequires:  texinfo

%description
The GNU Hello program produces a familiar, friendly greeting. Yes, this is
another implementation of the classic program that prints "Hello, world!" when
you run it.

%prep
%autosetup
mv THANKS THANKS.old
iconv --from-code=ISO-8859-1 --to-code=UTF-8 --output=THANKS THANKS.old

%build
%configure --enable-nls --disable-rpath
%make_build

%install
%make_install
test -f %{buildroot}/%{_infodir}/dir && rm %{buildroot}/%{_infodir}/dir
%find_lang %{name}

%check
make check

%files -f %{name}.lang
%{_mandir}/man1/hello.1.*
%{_infodir}/hello.info.*
%{_bindir}/hello
%doc AUTHORS ChangeLog NEWS README THANKS TODO
%license COPYING

%changelog
%autochangelog

Mit dieser .spec-Datei sollten Sie den Bauprozess erfolgreich abschließen und die Quell- und Binär-RPM-Pakete erstellen können.

Überprüfen des Ergebnisses

Das Ergebnis können Sie nun mit rpm überprüfen, wie es in Teil 1 getan wurde.

Dateien

Dateien auflisten, die im Paket enthalten sind:

$ rpm --query --package --list results_hello/2.10/1.fc42/hello-2.10-1.fc42.x86_64.rpm
/usr/bin/hello
/usr/lib/.build-id
/usr/lib/.build-id/39
/usr/lib/.build-id/39/c97ecb15c6292ce23e8b00e15e6e72a61e5072
/usr/share/doc/hello
/usr/share/doc/hello/AUTHORS
⋮
/usr/share/doc/hello/TODO
/usr/share/info/hello.info.gz
/usr/share/licenses/hello
/usr/share/licenses/hello/COPYING
/usr/share/locale/bg/LC_MESSAGES/hello.mo
⋮
/usr/share/locale/zh_TW/LC_MESSAGES/hello.mo
/usr/share/man/man1/hello.1.gz

Sie können sehen, dass alle im Abschnitt %files der Spec-Datei aufgeführten Dateien enthalten sind, einschließlich der automatisch verarbeiteten Locale-Dateien. Auch die Datei .build-id ist vorhanden, genau wie in Teil 1.

Requires und Provides

Mit den folgenden beiden Befehlen können Sie die Laufzeitabhängigkeiten des Pakets und die von ihm bereitgestellten Fähigkeiten auflisten. Die Ausgabe ähnelt der entsprechenden Ausgabe in Teil 1.

$ rpm --query --package --requires results_hello/2.10/1.fc42/hello-2.10-1.fc42.x86_64.rpm
$ rpm --query --package --provides results_hello/2.10/1.fc42/hello-2.10-1.fc42.x86_64.rpm

Installieren

Zur abschließenden Überprüfung kann das Paket installiert und ausgeführt werden:

$ sudo dnf -C -y install ./results_hello/2.10/1.fc42/hello-2.10-1.fc42.x86_64.rpm
$ hello --greeting="Hello, rpm!"
Hello, rpm!

Um Ihr System zu bereinigen, machen Sie die Installation rückgängig:

$ sudo dnf -C -y history undo last