Ubuntu logo

Packaging Guide

8. Gemeinsame Bibliotheken

Gemeinsame Bibliotheken sind kompilierter Code, der von vielen verschiedenen Programmen gemeinsam genutzt wird. Sie werden als .so-Dateien unter /usr/lib/ zur Verfügung gestellt.

Eine Bibliothek exportiert Symbole, welche die kompilierten Versionen von Funktion, Klassen und Variablen sind. Eine Bibliothek wird als SONAME bezeichnet und beinhaltet eine Versionsnummer. Dieser SONAME entspricht nicht zwingend der öffentlichen Versionsbezeichnung. Ein Programm wird gegen eine gegebene SONAME-Version der Bibliothek kompiliert. Wenn eines der Symbole entfernt oder geändert wird, muss die Versionsnummer angepasst werden, was dazu führt, dass jedes Paket welches die Bibliothek benutzt, wieder gegen die neue Version kompiliert werden muss. Versionsnummern werden normalerweise vom Upstream festgelegt und wir folgen ihnen mit unseren Binärpaketnamen, auch ABI-Nummer genannt. Aber manchmal benutzt der Upstream keine vernünftigen Versionsnummern und die Paketierer müssen einer getrennten Nummerierung folgen.

Bibliotheken werden normalerweise von Upstream als Einzelreleases verteilt. Manchmal werden sie auch als Teil einen Programms herausgegeben. In diesem Fall können sie einfach mit in das Programm-Paket integriert werden (wenn zu erwarten ist, dass kein anderes Programm diese Bibliothek benutzt). Meistens sollten sie jedoch getrennt werden und in gesonderte Pakete gepackt werden.

Die Bibliotheken selbst werden in einem Binärpaket mit dem Namen libfoo1 abgelegt, wobei foo der Name der Bibliothek und 1 die SONAME-Version ist. Entwicklungsdateien aus dem Paket, beispielsweise Kopfdateien, die benötigt werden, um Programme gegen die Bibliothek zu übersetzen, werden in einem Paket mit dem Namen libfoo-dev abgelegt.

8.1. Ein Beispiel

Wir werden libnova als Beispiel verwenden:

$ bzr branch ubuntu:trusty/libnova
$ sudo apt-get install libnova-dev

Um den SONAME der Bibliothek herauszufinden, starten Sie:

$ readelf -a /usr/lib/libnova-0.12.so.2 | grep SONAME

Der SONAME ist libnova-0.12.so.2, die dem Dateinamen entspricht (üblicherweise der Fall aber nicht immer). Hier hat Upstream die Versionsnummer als Teil des SONAME eingesetzt und ihm eine ABI-Version von 2 gegeben. Bibliothekspaketnamen sollten dem SONAME der Bibliothek folgenden, die sie beinhalten. Das Binärbibliothekspaket heißt libnova-0.12-2 wobei libnova-0.12 der Name der Bibliothek und 2 unsere ABI-Nummer ist.

Wenn im Upstream inkompatible Änderungen an den Bibliotheken durchgeführt werden, müssen sie eine neue Revision des SONAME erstellen und wir werden unsere Bibliothek umbenennen müssen. Jedes andere Paket welches unsere Bibliothek verwendet, muss dann wieder gegen die neue Version kompiliert werden; das nennt man Transition und kann einigen Aufwand verursachen. Im besten Fall bleibt unsere ABI-Nummer passend zu SONAME des Upstreams, aber manchmal führen sie Inkompatibilitäten ein ohne ihre Versionsnummer zu ändern und so müssen wir unsere anpassen.

Wenn wir uns debian/libnova-0.12-2.install ansehen, stellen wir fest, dass dort zwei Dateien eingebunden werden:

usr/lib/libnova-0.12.so.2
usr/lib/libnova-0.12.so.2.0.0

Das letzte ist die eigentliche Bibliothek, komplett mit Unter- und Punkversionsnummer. Das erste ist ein Symlink welcher auf die eigentliche Bibliothek verweist. Der Symlink ist das, nach dem die Programme welche Bibliothek benutzen suchen, sie kümmern sich nicht um die Unterversionsnummern.

libnova-dev.install beinhaltet alle benötigten Dateien um das Programm mit dieser Bibliothek zu kompilieren. Kopfdateien, eine Konfigurationsbinärdatei, die libtool Datei .la und libnova.so, welche als weiterer Symlink zu der Bibliothek führt; Programme die gegen die Bibliothek kompiliert werden kümmern sich nicht um die Hauptversionsnummer (jedoch wird das die Binärdatei in die sie kompilieren berücksichtigen).

.la libtool Datein werden auf manchen nicht-Linuxsystemen benötigt, die mangelnde Bibliotheksunterstützung haben aber verursachen normalerweise mehr Probleme auf Debiansystemen als sie lösen. Es ist ein aktuelles Debian Ziel, .la-Dateien zu entfernen und wir sollten dabei helfen.

8.2. Statische Bibliotheken

Das -dev Paket stellt außerdem usr/lib/libnova.a bereit. Dies ist eine statische Bibliothek, eine Alternative zu gemeinsamen Bibliotheken. Jedes gegen diese statische Bibliothek kompilierte Programm beinhaltet diesen Quelltext. Damit entfällt das Problem, die Bibliothek könnte als Binärdatei inkompatibel sein. Allerdings bedeutet dies auch, dass alle Fehler, die Sicherheitsprobleme inbegriffen, nicht behoben werden, solange das Programm nicht erneut kompiliert wird. Aus diesem Grund sind Programme, die statische Bibliotheken verwenden, zu vermeiden.

8.3. Symbol-Dateien

Wenn ein Paket gegen eine Bibliothek baut wird der shlibs Mechanismus eine Paketabhängigkeit auf diese Bibliothek hinzuzufügen. Aus diesem Grund haben die meisten Programme Depends: ${shlibs:Depends} in debian/control. Dies wird mit den Bibliotheksabhängigkeiten zur Bauzeit ersetzt werden. Trotzdem kann shlibs es nur auf die Major ABI Versionsnummer abhängen lassen, 2 in unsersem libnova Beispiel. Falls also neue Symbole in libnova 2.1 hinzugefügt werden kann ein Programm welches diese Symbole benutzt trotzdem gegen libnova ABI 2.0 installiert werden was dann einen Absturz zur Folge hat.

Um die Bibliotheksabhängigkeiten präzise zu halten, verwenden wir .symbols-Dateien, die alle Symbole in einer Bibliothek auflisten und in welcher Version sie zuerst auftauchten.

libnova hat keine Symboldatei, also können wir eine erstellen. Beginnen Sie damit das Paket zu kompilieren:

$ bzr builddeb -- -nc

Die Option -nc sorgt dafür, dass nach dem Kompilieren die Dateien des Programms, die währenddessen erzeugten wurden, nicht entfernt werden. Wechseln Sie in das Verzeichnis des Kompilierungsprozesses und führen Sie dpkg-gensymbols für das Bibliothekspaket aus:

$ cd ../build-area/libnova-0.12.2/
$ dpkg-gensymbols -plibnova-0.12-2 > symbols.diff

Dies erstellt eine Diff-Datei welche Sie selbst anwenden können:

$ patch -p0 < symbols.diff

Dies wird eine Datei erstellen die ähnlich dpkg-gensymbolsnY_WWI benannt wird, welche alle Symbole auflistet. Es listet auch die aktuelle Paketversion auf. Wir können die Paketierungsversion von derjenigen, die in der symbols Datei aufgelistet ist, entfernen da neue Symbole nicht allgemein durch neue Paketierungsversionen hinzugefügt werden sondern von den Upstream Entwicklern:

$ sed -i s,-0ubuntu2,, dpkg-gensymbolsnY_WWI

Nun verschieben Sie die Datei an ihren Ort, comitten und machen einen Testlauf:

$ mv dpkg-gensymbolsnY_WWI ../../libnova/debian/libnova-0.12-2.symbols
$ cd ../../libnova
$ bzr add debian/libnova-0.12-2.symbols
$ bzr commit -m "add symbols file"
$ bzr builddeb

Wenn es erfolgreich kompiliert, ist die Symboldatei in Ordnung. Mit der nächsten Upstream-Version von libnova würden Sie erneut dpkg-gensymbols ausführen und es liefert eine Auflistung der Unterschiede um die Symboldatei zu aktualisieren.

8.4. C++-Bibliothek-Symboldateien

C++ hat sogar noch genauere Binärkompatibilitäts-Standards als C. Das Debian Debian Qt/KDE Team wartet einige Skripte um dies zu verwalten. Schauen Sie ihre Working with symbols files Seite an wie man diese verwendet.

8.5. Weiterführende Literatur

Junichi Uekawa’s Debian Library Packaging Guide geht bei diesem Thema stärker ins Detail.