openSUSE:Paketbau-Richtlinie für mehrfach benutzte Bibliotheken
Inhaltsverzeichnis
Begründung
Das Schema macht es möglich, mehrfach benutzte Bibliotheken mit der gleichen Grundbezeichnung, aber unterschiedlicher so-Version, z.B. einer älteren Distribution, für den Fall es gibt Programme, die sie benötigen, zu installieren und zu verwenden. Ein Diskriminator muß Teil der Paketbezeichnung sein, da andererseits das Aktualisierungsbündel durcheinander gebracht wird. Und die Verwendung monoton steigender Zahlen macht Sinn. Eine strikte Struktur für Paketbezeichnungen wird ebenso den Anwendern helfen, "quick & dirty" Werkzeuge zu schreiben.
Daraus folgt, dass nur Dateien einbezogen werden sollten, die später keine Dateikonflikte verursachen, wenn sie mit einem anderen libfoo*.rpm installiert sind. Darum sind darin nur lib*.so.* Dateien erlaubt. Um sicher zu stellen, dass sich keine mehrfach benutzte Bibliotheken einschleichen, die nicht gehandhabt werden können, erlauben wir ihnen nicht, in einem Paket zu sein, die nicht nach diesen Regeln bezeichnet sind.
Das erzeugt eine Aufteilung von allen Dateien in mehrfach benutzten Bibliotheken und anderen und stellt sicher, dass kein RPM Dateien aus beiden Aufteilungen enthält.
Versionierungsschemen
Die prinzipielle Regel der Versionierung besteht darin, dass das Löschen oder Ändern der ABI auf einer inkompatiblen Weise einen neuen, anderen SONAME erfordert.
$ readelf -a /usr/lib64/libHX.so | grep SONAME 0x000000000000000e (SONAME) Library soname: [libHX.so.28]
Wenn es keinen SONAME-Eintrag gibt, wird die Dateibezeichnung selbst als SONAME verwendet.
Verwendung von Libtool
Viele Pakete wählen das folgende Konzept des Liptools von so genannten Schnittstellen und Schnittstellennummern, wie es unter Libtool Anleitung beschrieben wird. Das kann erkannt werden an den -version-info und/oder -release Markierungen in den Makefiles. Als Entwickler und/oder Paketbauer beachten Sie bitte, dass die Versionsinformation könnte auf verschiedenen Plattformen unterschiedlich verschlüsselt sein (aber noch konsequent) z. B.
-version-info c:r:a | First int'f | Last int'f | Linux | FreeBSD |
---|---|---|---|---|
7:0:0 | 7 | 7 | .so.7.0.0 | .so.7 |
8:0:1 | 7 | 8 | .so.7.1.0 | .so.8 |
9:0:2 | 7 | 9 | .so.7.2.0 | .so.9 |
9:0:1 | 8 | 9 | .so.8.1.0 | .so.9 |
9:0:0 | 9 | 9 | .so.9.0.0 | .so.9 |
Es ist darum ein Fehler den Wert c:r:a so verbessern zu wollen, dass man eine spezielle SO-Nummer bekommt. Das riecht danach, das Schnittstellenkonzept nicht verstanden zu haben.
Das Manual außer Kraft setzen
Einige Quellpakete wollen die SO-Nummer direkt manuell definieren. Pakete die wünschen, das so zu machen, können die -version-number von Libtool verwenden. Sie sollten in diesem Fall nicht -version-info verwenden, um zu vermeiden, beschuldigt zu werden, beim Einrichten und/oder Ändern von c:r:a auf undurchsichtige Weise einen unausweichlichen Fehler gemacht zu haben.
Während die Libtool-Anleitung in gewisser Weise entmutigt, diese Option zu verwenden (Zitat: "Neue Projekte sollten stattdessen die -version-info Markierung verwenden."), bedeutet es nicht, dass die Option abgelehnt wird; sie möchte einfach, dass alle natürlich übertragbar sind.
Wenn es keine Versionierung gibt
Manche Quellpakete können in einem Zustand sein, dass eine oder mehrere der folgenden Aussagen zutrifft:
- Die Quelle könnte keine gemeinsam benutzte Bibliotheken erzeugen, mit denen zu starten ist. Der Distromanager beabsichtigt sie selbst zu erzeugen.
- Der Upstream kümmert sich nicht um die Versionierung, beispielsweise produziert eine Bibliothek, die den gleichen SONAME (der keinen SONAME) hat, trotzdem ändert sich die ABI über verschiedene Ausgaben.
- Upstream vergass, seine Nummerierungen für spezielle Ausgaben zu aktualisieren.
In solchen Fällen empfiehlt die Anleitung von Libtool, den sichersten Aktionsweg ist es, die Paketversion in die Bezeichnung hinzu zu fügen (das kann mit oder ohne Libtool gemacht werden, BTW). libfoo.so soll dann libfoo-2.5.0.so werden (wenn die Paketversion 2.5.0.war). Ein bekanntes Beispiel für dieses Schema ist Libbfd von Binufils (/usr/lib(64)/libbfd*.so).
Dieses Schema erfordert keine Koordination mit anderen Parteien, um gleichzeitig universell und übertragbar auf andere Linux-Distributionen zu sein.
Paketbenennung
Der Name einer Bibliothek, speziell sein SONAME, der als Basis verwendet wird, um die versionierte Paketbezeichnung zu konstruieren, kann aus mehreren Teilen (nicht alle werden gefordert) zusammengesetzt werden. Schauen wir auf ein komplett ausgeführtes Beispiel. Der Dateiname wie libfoo-bar-2.5.so.8.2.1 enthält:
- den generellen Systempräfix lib
- die Bezeichnung der Bibliothek: foo-bar
- die Paketversion (optional): -2.5
- das generelle Systemsuffix für mehrfach benutzte Bibliotheken: .so
- die SO-Version (optional): 8.2.1
Die Bezeichnung des Distributionspaketes wird vom Dateinamen abgeleitet und durch Verknüpfung zusammengesetzt:
- Das lib Präfix und der Name, Punkte werden durch Unterstriche ersetzt;
- Wenn eine Upstreamversion spezifiziert wird, werden Punkte durch Unterstriche ersetzt;
- Um Mehrdeutigkeiten zu vermeiden, wird ein Bindestrich zwischen zwei Zahlen eingefügt;
- Die SO-Version von SONAME (welche kürzer sein könnte als die Dateibezeichnung), Punkte werden durch Unterstriche ersetzt;
Alle Möglichkeiten mit Beispielen werden meist von openSUSE genommen:
Beschreibung | SONAME | Versioniete Paketbezeichnung in Distro |
---|---|---|
Nichts | libdsocks.so | (shlib Paketbau nicht anwendbar) |
Mit Paketversion | libdb-4.8.so | libdb-4_8 |
Mir SO-Version | libblkid.so.1 | libblkid1 |
Name mit Zahl und SO-Version | libbz2.so.1 | libbz2-1 |
Mit Version und SO-Version | libzziplib-0.so.13 | libzziplib-0-13 |
Alles zusammen und lange SO-Nummer | libgame2-1.9.so.10.0.0 | libgame2-1_9-10_0_0 |
Anmerkung: Der scharfsinnige Leser könnte bemerkt haben, dass diese Zuordnung nicht eineindeutig (1:1) ist. Die hypothetische Dateibezeichnungen libgame3.so.1 und libgame3-1.so würden tatsächlich zur gleichen shlib Paketbezeichnung (libgame3-1) führen. Das ist für diese Richlinie nicht vorgesehen. Aber eine solche Situation könnte in der Praxis auftreten. Wo so etwas auftritt, sollten wir das zweite Paket patchen, um libgame3-1.so.0 anstelle von libgame3-1.so zu produzieren, um das Problem zu lösen.
Nicht versionierte Pakete
Versionierte Pakete werden so bezeichnet, weil sie alles oder einen Teil einer Version in ihrer Bezeichnung enthalten. Das Gegenteil davon sind nicht versionierte shlib Pakete, für die der größte Teil diese Dokuments nicht anwendbar ist. Beispiele für solche Pakete sind: bind-libs, cups-libs. Seit die shlib-Richtlinie formuliert wurde, versuchen wir, nicht versionierte shlib-Pakete zu vermeiden oder zu eliminieren, innerhalb der Grenzen des gesunden Menschenverstandes - und einem guten Gefühl, wann es besser ist, die nicht versionierten Pakete zu behalten.
Wählbarkeit
(Das ist eine Absicht den den Abschnitt "Paketinhalt" teilweise neu zu schreiben, in einfacher Form unter Verwendung des Ausschlussprinzips.)
- Wenn die in Frage kommende gemeinsam benutzte Bibliothek ein Plugin ist ("Modul" in Libtool-Fachsprache), ist die Shlib-Richtlinie nicht anwendbar - aber schauen Sie sich die Hinweise im Abschnitt “Plugins” unten an.
- Wenn es kein korrespondierendes Paket -devel für die gemeinsam benutzte Bibliothek gibt, sollte die Bibliothek in das gleiche Paket wie das Haupt-RPM platziert werden. (Beispiel: Paket encfs von openSUSE 12.1)
Paketinhalt
- Grundsätzlich sollten versionierte Pakete nichts außer die gemeinsam benzuzte/n Bibliothek/en enthalten, keinen Symlink devel .so, keine Konfigurationsdatei, keine Dokumentation, etc.
- Es kann, wenn gefordert, die Lizenzdatei enthalten und muss in einem versionierten Verzeichnis sein. (Die Verwendung von "%doc LICENSE" in einem Dateiabschnitt der Spezifikationsdatei ist gewöhnlich ausreichend.)
- Wenn aus irgend einem (zugelassenen!) Grund ein versioniertes mehrfach benutztes Bibliothekspaket andere Dateien als gemeinsam benutzte Bibliotheken enthalten muss, muss ihre Bezeichnung eindeutig gemacht werden, indem sie in ein versioniertes Verzeichnis getan werden oder durch Versionierung ihrer Bezeichnungen, um nicht mit den Beziehungen dieser Richtlinie in Konflikt zu geraten.
- Die (einfache) Alternative: Lassen Sie das Paket shlib ein anderes Paket (es kann nicht versioniert sein) für solche Dateien anfordern, wenn so unterstützt.
- Es ist einem versionierten Paket erlaubt, mehrere Bibliotheksdateien auszuliefern, vorausgesetzt sie haben die gleiche Nummerierung und diese Nummern ändern sich immer im gleichen Schritt. (Beispiel: das Paket libqt4 liefert libQtCore.so.4, libQtNetwork.so.4 etc.)
- Wenn einer der enthaltenen Bibliotheken keine Abhängigkeit zu allen oder den meisten anderen enthaltenen Bibliotheken erzeugt, dann ist es vorteilhaft, diese Bibliotheken nicht in ein RPM zu stecken, sondern sie in ihrem eigenen RPM zu belassen. Berücksichtigen Sie die Installationsgröße.
- Alle Pakete ohne Suffix mit der Bezeichnung lib* enden mit $NUM
- Gewöhnliche Suffixe enthalten beispielsweise -devel oder -debuginfo
- Pakete mit Suffix -devel sollten grundsätzlich $NUM weglassen, ebenso wie Pakete mit -devel für verschiedene Bibliotheksversionen auf Grund gewöhnlicher Header-Dateinamen einen Konflikt verursachen. Lesen Sie (4a) und (4b), wie es anders funktioniert.
- Dateien, die benötigt werden, um Programme zu entwickeln, die gemeinsam benutzte Bibliotheken in lib$NAME$NUM.rpm enthalten, werden in ein Paket -devel gepackt (lesen Sie (4a) und (4b) für Fälle, die dieses Paket versionieren müssen). Diese Dateien enthalten lib*.so, lib*.la und alle Header. Optional können diese Dateien in $NAME.rpm platziert werden, für den Fall sie kommen mit anderen Werkzeugen oder Dokumentation. Aber wenn es ein *-devel.rpm-Paket gibt, dann enthält es alle lib*.so, lib*.la und Header. Das -devel-Paket ist ebenso ein geeigneter Ort, um Lizenzdateien unter zu bringen.
- Es sollte für irgend einen Anwender nicht nötig sein, lib$NAME$NUM.rpm manuell zu installieren. Die richtige RPM-Gruppe für solche Pakete ist System/Libraries.
Beste Vorgehensweisen
Das Folgende sind Richtlinien zum grundsätzlichen Paketbau von Bibliotheken:
- Vermeiden Sie den Paketbau von statischen Bibliotheken. Sie sollten die folgende Konfigurationsoption --disable-static als letzten Ausweg verwenden. Löschen Sie statische Bibliotheken nach %makeinstall. Wenn Sie unschlüssig sind, fragen Sie nach.
- Wenn Sie eine statische Bibliothek zusätzlich zu einer mehrfach benutzten packen, sollte die statische Bibliothek nicht mit -fPIC gebaut werden.
- Wenn Sie eine statische Bibliothek ohne eine korrespondierende gemeinsam benutzte packen, muss die statische Bibliothek mit -fPIC, wenn möglich unter Verwendung der Konfigurationsoption --with-pic, gebaut werden.
- Vermeiden Sie das Packen der Libtool-Konfigurationsdatei (.la files). Grundsätzlich werden sie nicht gebraucht, wenn Sie keine statische Bibliothek packen und' die .so-Datei in ein Systemverzeichnis (beispielsweise %_lib, /usr/%_lib) ablegen. Wenn sich Ihre gemeinsam benutzte Bibliothek aus irgend einem Grund in zum Beispiel /opt/package/lib/libfoo.so.7 befindet, brauchen Sie die Datei libfoo.la oder weiter Programme, die Libtool verwenden, um damit zu verlinken, da libfoo.so.7 den richtigen Pfad verfehlen wird.
- Im Zweifelsfall fragen Sie bitte.
- Gemeinsam benutzte Bibliotheken sind normaler Weise allein nicht lauffähig (Ausnahme: libc.so.6 und ld-linux.so.2). Aber sie haben oft das +x-Bit gesetzt!
Ausnahmen
- (2) Eine Liste von Paketen, die von dieser Richtlinie ausgenommen sind, ist: (nur mit ausdrücklicher Genehmigung verlängerbar)
- glibc
- pam
- (4a) Wenn mehr als eine Version einer Bibliothek aus einem einzigen Quellrepository zur Verfügung steht und auch Konflikte verursachende -devel-Pakete müssen mit einem Suffix versehen werden, um mehrere Pakete mit der gleichen Paketbezeichnung zu vermeiden. Angemessene Konflikte müssen in diesem Fall ebenso hinzugefügt werden.
- (4b) Wenn mehr als eine Version eines -devel-Paketes zur gleichen Zeit installiert werden können (zum Beispiel weil Einfügungen in ein versioniertes Verzeichnis gepackt sind und gemeinsam benutzte Bibliotheken eine versionierte Bezeichnung wie libgtk1.so.1 haben), sollten die -devel-Pakete mit einem Suffix versehen werden, deren Zahl es erlaubt, die Version der Bibliothek zu identifizieren (gewöhnlich ist das die gleiche Zahl wie das Suffix $NUM der gemeinsam benutzten Bibliothek). Solch ein -devel-Pakete würde man mit lib$NAME$NUM-devel bezeichnen.
Plugins
Plugins in der Form von gemeinsam benutzten Bibliotheken sollten in einem Unterverzeichnis %_libdir des entsprechenden Programms sein. (Beispiel: %_libdir/apache2/mod_alias.so).
In Automake (seit 0.25) steht die Variable ${pkglibdir} für diesen Zweck zur Verfügung. Es wird ${libdir}/${PACKAGE} als Standardeinstellung übernommen und könnte aufgehoben werden müssen, wenn das Plugin in einem Tar-Archiv getrennt von der Hauptquelle des Programms ausgeliefert wird.
Plugins in der Form von ausführbaren Programmen sollten in einem Unterverzeichnis %_libexecdir des entsprechenden Programms sein. (Beispiel: %_libexecdir/cups/filter/pdftops).
In Automake (seit 1.10b), steht die Variable ${pkglibexecdir} für diesen Zweck zur Verfügung.
Hinweise
Sie sollten sich an folgendes erinnern, wenn Sie versuchen diese Richtlinie anzuwenden:
- Es gibt keinen Grund, warum ein -devel-Paket nicht Entwicklungsdateien für mehrere gemeinsam benutzte Bibliothekspakete unterstützen kann.
- Es gibt keine Notwendigkeit, ein Binärpaket zu haben, dass mit der Bezeichnung des Quellpaketes übereinstimmt. Tatsächlich sollten Sie vermeiden das Quellpaket für unterschiedliche Versionen umzubenennen, wie wir es bevorzugen, um nur eine einzige Paketversion im Quellrepository zu haben.
- Abhängigkeiten zum gemeinsam benutzten Paket resultieren entweder von automatischen Abhängigkeiten, die von RPM erzeugt werden, wenn sie verwendet werden oder von einzelnen anderen Fällen, dem Bibliothekspaket -devel, das das gemeinsam benutzte Bibliothekspaket benötigen sollte, mit einer geeigneten versionierten Anforderung.
- Diese Richtlinie und seine Durchsetzung bezieht sich nur auf gemeinsam benutzte Bibliothekspakete, die unter /%_lib oder /usr/%_lib angeordnet sind. Regeln, die auf andere Teile anzuwenden sind, beziehen sich auf beste Erfahrungen und Richtlinien, die irgendwo anders vorhanden sind.
Beispiele
Das einfachste Beispiel ist ein Quellpaket, das eine einzige gemeinsam benutzte Bibliothek und Entwicklungsdateien baut (das Paket zlib passt zu diesem Beispiel). Die sich ergebenden Binärpakete sollten mit libz1 und libz-devel bezeichnet werden, mit den folgenden Inhalten (Dateiliste gekürzt):
libz1:
/lib/libz.so.1 /lib/libz.so.1.2.3
libz-devel:
/usr/lib/libz.so /usr/lib/libz.a /usr/include/zlib.h /usr/share/man/man3/zlib.3.gz /usr/share/doc/packages/zlib/algorithm.txt
Ein komplizierteres Beispiel ist, wenn es neben der Bibliothek und den Entwicklungsdateien ebenso ausführbare Programme und eine Dokumentation gibt (das Paket bzip2 passt zu diesem Beispiel):
libbz2-1:
/lib/libbz2.so.1 /lib/libbz2.so.1.0.0
libbz2-devel:
/usr/include/bzlib.h /usr/lib/libbz2.so /usr/lib/libbz2.a
bzip2:
/usr/bin/bzip2 /usr/share/man/man1/bzip2.1.gz
bzip2-doc:
/usr/share/doc/packages/bzip2-doc/manual.ps.gz
Die Dokumentation könnte entweder mit dem Binärpaket bzip2 oder dem Entwicklungspaket libbz2-devel zusammen gelegt sein, wenn ausreichend klein und damit verbunden.
Ein anderes Beispiel ist eine Bibliothek, die von der Konfiguration oder von Datendateien abhängt, die mit anderen Versionen der Bibliothek benutzt werden kann (das Paket curl passt zu diesem Beispiel). In diesem Fall sollten die Konfigurations- und die Datendateien in getrennte Pakete aufgespalten werden und die gemeinsam benutzte Bibliothek sollte das anfordern. Zum Beispiel hat Curl die vier Pakete libcurl4, libcurl-devel, curl und curl-ca-bundle (CA Zertifikate gefordert von libcurl4).