Kapitel 3. Den Quellcode verändern

Inhaltsverzeichnis

3.1. Einrichten von quilt
3.2. Fehler in den ursprünglichen Quellen korrigieren
3.3. Installation von Dateien in ihr Zielverzeichnis
3.4. Unterschiedliche Bibliotheken

Bitte beachten Sie, dass an dieser Stelle nicht auf alle Details eingegangen wird, wie die ursprünglichen Quellen korrigiert werden können, aber hier sind ein paar grundlegende Schritte und Probleme, auf die man häufig stößt.

Das Programm quilt bietet eine grundlegende Methode, um Änderungen an den ursprünglichen Quellen für das Debian-Paket aufzuzeichnen. Es ist sinnvoll, eine leicht geänderte Voreinstellungen zu verwenden, daher sollte ein Alias dquilt für die Debian-Paketierung erstellt werden, indem folgendes zur ~/.bashrc hinzugefügt wird; dabei stellt die zweite Zeile die gleichen Shell-Vervollständigungsfunktionalität wie der Befehl quilt für den Befehl dquilt bereit:

alias dquilt="quilt --quiltrc=${HOME}/.quiltrc-dpkg"
complete -F _quilt_completion $_quilt_complete_opt dquilt

Dann erstellen Sie die ~/.quiltrc-dpkg wie folgt:

d=. ; while [ ! -d $d/debian -a `readlink -e $d` != / ]; do d=$d/..; done
if [ -d $d/debian ] && [ -z $QUILT_PATCHES ]; then
    # falls in Debian-Paketbaum mit ungesetztem $QUILT_PATCHES
    QUILT_PATCHES="debian/patches"
    QUILT_PATCH_OPTS="--reject-format=unified"
    QUILT_DIFF_ARGS="-p ab --no-timestamps --no-index --color=auto"
    QUILT_REFRESH_ARGS="-p ab --no-timestamps --no-index"
    QUILT_COLORS="diff_hdr=1;32:diff_add=1;34:diff_rem=1;31:diff_hunk=1;33:diff_ctx=35:diff_cctx=33"
    if ! [ -d $d/debian/patches ]; then mkdir $d/debian/patches; fi
fi

Siehe quilt(1) und /usr/share/doc/quilt/quilt.pdf.gz für eine Anleitung, wie quilt benutzt wird.

Nehmen wir an, Sie finden den folgenden Fehler in der ursprünglichen Makefile, wo statt »install: gentoo« besser »install: gentoo-target« stehen sollte.

install: gentoo
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc

Wir beheben dies und speichern es mit dem Befehl quilt wie folgt als fix-gentoo-target.patch. [22]

$ mkdir debian/patches
$ dquilt new fix-gentoo-target.patch
$ dquilt add Makefile

Sie können die Datei Makefile wie folgt ändern.

install: gentoo-target
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc

Jetzt muss dquilt noch mitgeteilt werden, dass der Patch erzeugt werden soll, so dass die Datei debian/patches/fix-gentoo-target.patch erstellt wird. Außerdem sollen Sie eine Beschreibung gemäß DEP-3: Patch Tagging Guidelines hinzufügen.

$ dquilt refresh
$ dquilt header -e
... Patch beschreiben

Die meisten Programme Dritter installieren sich in die Verzeichnishierachie /usr/local. Unter Debian ist diese für die private Benutzung durch den Systemadministrator reserviert, daher dürfen Pakete Verzeichnisse wie /usr/local/bin nicht verwenden, sondern sollten stattdessen Systemverzeichnisse wie /usr/bin verwenden und dem Filesystem Hierarchy Standard (FHS) folgen.

Normalerweise wird make(1) benutzt, um das Programm automatisch zu bauen. Der Aufruf von »make install« installiert das Programm dann direkt in das Ziel (gemäß dem install-Ziel der Makefile). Damit Debian vorab erstellte installierbare Pakete bereitstellen kann, verändert es das Bausystem, um Programme in ein Dateisystem-Abbild, welches unter einem temporären Verzeichnis erstellt wurde, anstatt an das tatsächliche Ziel zu installieren.

Diese beiden Unterschiede zwischen einerseits der normalen Programminstallation und andererseits dem Paketieren für Debian können vom Paket Debhelper transparent adressiert werden. Es benutzt dazu die Befehle dh_auto_configure und dh_auto_install, sofern die folgenden Bedingungen erfüllt sind.

  • Das Makefile muss den GNU-Konventionen folgen und die Variable $(DESTDIR) unterstützen. [23]

  • Die Quelle muss dem »Filesystem Hierarchy Standard« (FHS) folgen.

Programme, die GNU autoconf einsetzen, folgen automatisch den GNU-Konventionen, so dass sie trivial zu paketieren sind. Auf Grund dieser Tatsache und weiterer Heuristik wird geschätzt, dass das Paket debhelper für ungefähr 90% aller Pakete richtig funktionieren wird, ohne dass irgendwelche tiefgreifenden Änderungen an deren Build-System vorgenommen werden müssen. Daher ist das Paketieren nicht so kompliziert, wie es zunächst aussieht.

Falls Sie Änderungen an dem Makefile vornehmen müssen, sollten Sie vorsichtig sein, dass die Variable $(DESTDIR) unterstützt wird. Obwohl sie standardmäßig nicht gesetzt ist, wird die Variable $(DESTDIR) jedem Dateipfad vorangestellt, der für die Programminstallation verwendet wird. Das Skript für das Paketieren setzt $(DESTDIR) auf das temporäre Verzeichnis.

Bei einem Quellpaket, das ein einzelnes Binärpaket erstellt, wird das temporäre Verzeichnis, das vom Befehl dh_auto_install benutzt wird, auf debian/Paket gesetzt. [24] Alles, was im temporären Verzeichnis enthalten ist, wird auf dem System eines Benutzers installiert, wenn dieser Ihr Paket installiert. Der einzige Unterschied ist, dass dpkg die Dateien relativ zum Wurzelverzeichnis statt zu Ihrem Arbeitsverzeichnis installieren wird.

Vergessen Sie nicht, dass Ihr Programm zwar unter debian/Paket installiert wird, es sich aber trotzdem korrekt verhalten muss, wenn es aus dem .deb-Paket unter dem Wurzelverzeichnis installiert wird. Daher dürfen durch das Build-System keine fest eingestellten Zeichenketten wie /home/ich/deb/Paket-Version/usr/share/Paket in Dateien im Paket geschrieben werden.

Dies ist der relevante Abschnitt aus dem Makefile[25] von gentoo:

# Where to put executable commands on 'make install'?
BIN     = /usr/local/bin
# Where to put icons on 'make install'?
ICONS   = /usr/local/share/gentoo

Sie sehen, dass die Dateien unter /usr/local installiert werden sollen. Wie oben erklärt ist diese Verzeichnis-Hierarchie unter Debian für lokale Benutzung reserviert, ändern Sie daher diese Pfade in:

# Where to put executable commands on 'make install'?
BIN     = $(DESTDIR)/usr/bin
# Where to put icons on 'make install'?
ICONS   = $(DESTDIR)/usr/share/gentoo

Der genaue Ort, der für Programme, Icons, Dokumentation usw. verwandt werden sollte, ist im »Filesystem Hierarchy Standard« (FHS) spezifiziert. Sie sollten ihn durchblättern und die für Ihr Paket relevanten Abschnitte lesen.

Sie sollten also ausführbare Befehle in /usr/bin/ statt /usr/local/bin/ installieren, die Handbuchseiten in /usr/share/man/man1/ statt /usr/local/man/man1/ usw. Beachten Sie, dass im Makefile von gentoo keine Handbuchseite auftaucht. Da die Debian-Richtlinien aber verlangen, dass jedes Programm eine hat, schreiben Sie später eine und installieren sie unter /usr/share/man/man1/.

Manche Programme nutzen die Makefile-Variablen nicht, um solche Pfade zu definieren. Das bedeutet, dass Sie wahrscheinlich die C-Quelltexte direkt bearbeiten müssen, damit diese dann die richtigen Pfade benutzen. Aber wo soll man suchen, und wonach eigentlich genau? Sie können dies herausfinden, indem Sie folgendes eingeben:

$ grep -nr --include='*.[c|h]' -e 'usr/local/lib' .

Grep durchsucht das Quellverzeichnis rekursiv und gibt Ihnen den Dateinamen und die Zeilennummer für alle Treffer aus.

Sie müssen diese Dateien nun bearbeiten und in den entsprechenden Zeilen usr/local/lib durch usr/lib ersetzen. Dies kann wie folgt automatisch erledigt werden:

$ sed -i -e 's#usr/local/lib#usr/lib#g' \
        $(find . -type f -name '*.[c|h]')

Falls Sie stattdessen jede Ersetzung bestätigen möchten, kann dies wie folgt interaktiv durchgeführt werden:

$ vim '+argdo %s#usr/local/lib#usr/lib#gce|update' +q \
        $(find . -type f -name '*.[c|h]')

Als nächstes sollten Sie das »install«-Ziel suchen (suchen Sie nach der Zeile, die mit install: beginnt, das funktioniert üblicherweise) und alle Verweise auf Verzeichnisse umbenennen, die nicht denen entsprechen, die Sie am Anfang der Makefile definiert haben.

Ursprünglich sah das install-Ziel von gentoo wie folgt aus:

install: gentoo-target
        install ./gentoo $(BIN)
        install icons/* $(ICONS)
        install gentoorc-example $(HOME)/.gentoorc

Wir beheben diesen Fehler der Originalautoren und speichern es mit dem Befehl dquilt als debian/patches/install.patch.

$ dquilt new install.patch
$ dquilt add Makefile

Wir ändern dies für das Debian-Paket im Editor wie folgt:

install: gentoo-target
        install -d $(BIN) $(ICONS) $(DESTDIR)/etc
        install ./gentoo $(BIN)
        install -m644 icons/* $(ICONS)
        install -m644 gentoorc-example $(DESTDIR)/etc/gentoorc

Sie haben bemerkt, dass jetzt der Befehl »install -d« vor den anderen Befehlen in dieser Regel steht. Das ursprüngliche Makefile hatte das nicht, weil normalerweise /usr/local/bin/ und andere Verzeichnisse schon auf dem System vorhanden sind, wenn Sie »make install« aufrufen. Weil wir aber in unseren frisch erstellten Verzeichnisbaum installieren, müssen wir jedes einzelne dieser Verzeichnisse anlegen.

Wir können am Ende der Regel noch weitere Dinge einfügen, wie beispielsweise die Installation zusätzlicher Dokumentation, die die Originalautoren manchmal weglassen:

        install -d $(DESTDIR)/usr/share/doc/gentoo/html
        cp -a docs/* $(DESTDIR)/usr/share/doc/gentoo/html

Überprüfen Sie sorgfältig und falls alles in Ordnung ist, bitten Sie dquilt, den Patch zu erstellen und die Datei debian/patches/install.patch neu zu erstellen. Fügen Sie außerdem noch eine Beschreibung hinzu.

$ dquilt refresh
$ dquilt header -e
... Patch beschreiben

Jetzt haben Sie eine Reihenfolge von Patches.

  1. Die Fehlerkorrektur der originalen Quellen: debian/patches/fix-gentoo-target.patch

  2. Die Debian-spezifische Änderung für's Paketieren: debian/patches/install.patch

Wann immer Sie Änderungen machen, die nicht spezifisch für das Debian-Paket sind (so wie debian/patches/fix-gentoo-target.patch), sollten Sie diese dem Betreuer des Originalprogramms zukommen lassen, damit er sie in der nächsten Programmversion verwenden kann und sie für andere auch nützlich sind. Denken Sie auch daran, Ihre Patches nicht spezifisch für Debian oder Linux (oder sogar Unix!) zu gestalten, sondern sie portierbar zu erstellen. Dadurch können Ihre Änderungen wesentlich leichter übernommen werden.

Beachten Sie, dass Sie dem Originalautoren die debian/*-Dateien nicht schicken müssen.

Es gibt ein anderes typisches Problem: Bibliotheken variieren oft von Plattform zu Plattform. Beispielsweise kann ein Makefile eine Referenz auf eine Bibliothek enthalten, die auf Debian-Systemen nicht existiert. In diesem Fall müssen wir sie auf eine Bibliothek ändern, die unter Debian existiert und den gleichen Zweck erfüllt.

Nehmen wir an, eine Datei in dem Makefile (oder Makefile.in) Ihres Programms lautet wie folgt:

LIBS = -lfoo -lbar

Falls Ihr Programm nicht übersetzt, da die Bibliothek foo nicht existiert und auf Debian-Systemen ihr äquivalent von der Bibliothek foo2 bereitgestellt wird, können Sie dieses Bauproblem mittels debian/patches/foo2.patch beheben, indem Sie foo in foo2 ändern. [26]

$ dquilt new foo2.patch
$ dquilt add Makefile
$ sed -i -e 's/-lfoo/-lfoo2/g' Makefile
$ dquilt refresh
$ dquilt header -e
… Patch beschreiben


[22] Das Verzeichnis debian/patches sollte inzwischen existieren, wenn Sie dh_make wie vorher beschrieben ausgeführt haben. In diesem Beispiel wird es sicherheitshalber erstellt, nur für den Fall, dass Sie ein existierendes Paket aktualisieren.

[24] Bei einem Quellpaket, das mehrere Binärpakete erstellt, verwendet der Befehl dh_auto_install das temporäre Verzeichnis debian/tmp. Der Befehl dh_install teilt dann den Inhalt von debian/tmp mit Hilfe von debian/Paket-1.install und debian/Paket-2.install in die temporären Verzeichnisse debian/Paket-1 und debian/Paket-2 auf, um daraus die Binärpakete Paket-1_*.deb und Paket-2_*.deb zu erstellen.

[25] Dies ist nur ein Beispiel, wie ein Makefile aussehen sollte. Falls die Makefile-Datei durch den Befehl ./configure erstellt wird, ist die richtige Vorgehensweise, um diese Art Makefile zu korrigieren, ./configure durch den Befehl dh_auto_configure aufrufen zu lassen. Dabei kommen die voreingestellten Optionen zum Tragen, einschließlich der Option --prefix=/usr.

[26] Falls es API-Änderungen von der Bibliothek foo zu der Bibliothek foo2 gibt, müssen die Quellen entsprechend angepasst werden, um auf die neue API zu passen.