[OpenBSD]

Wie man mit Shared Librarys im Ports-Tree umgeht

Die Shared-Librarys-Nummerierungsregel verstehen

Shared Librarys sind aus einer Reihe Gründe knifflig. Du musst das Bibliotheks-Namensschema verstehen: libfoo.so.major.minor.

Wenn du ein Programm verlinkst, bettet der Linker ld diese Information in die erzeugte Binary. Du kannst sie mit ldd sehen. Später, wenn du das Programm ausführst, verwendet der dynamische Linker ld.so diese Information, um die richtige dynamische Bibliothek zu finden:

Dies heißt also, dass alle Bibliotheken mit der gleichen Hauptnummer und einer gleichen oder höheren Unternummer der binären API entsprechen müssen, die das Programm erwartet. Wenn sie es nicht tun, ist dein Port kaputt (broken). Insbesondere wird er kaputt gehen, wenn Benutzer versuchen, ihr System zu aktualisieren.

Die Regeln für Shared Librarys sind recht einfach.

Ab und zu kann es vorkommen, dass eine Bibliothek in mehrere Dateien geschrieben wird und dass interne Funktionen sichtbar sind, damit sie zwischen jenen Dateien kommunizieren können. Solche Funktionsnamen beginnen üblicherweise mit einem Unterstrich und sind kein ordentlicher Teil der API.

Bedenke, dass das Bibliotheks-Namensschema allgegenwärtig auf OpenBSD-Plattformen ist, gleich, ob sie ELF oder a.out verwenden.

Ports-,builds' optimieren, um richtige Namen zu erzielen

So manche Ports benötigen Optimierungen, um Shared Librarys überhaupt korrekt erzeugt werden zu können. Denke daran, dass das Erzeugen von Shared Librarys mit gcc -shared -fpic|-fPIC -o libfoo.so.4.5 obj1 obj2 erfolgen sollte.

Zu versuchen, die Bibliothek nach der Erzeugung umzubenennen, um so die Versionsnummer anzupassen, funktioniert nicht: ELF-Bibliotheken verwende einige extra ,magic', um den bibliotheksinternen Namen zu setzen, sodass du sie mit der korrekten Version gleich beim ersten Mal richtig linken musst.

Auf der anderen Seite musst du bedenken, dass du Makefile-Variablen von der Kommandozeile aus überschreiben kannst, indem du MAKE_FLAGS in dem Makefile des Ports verwendest. Dies ist recht nützlich, zum Beispiel, in den libtool-basierten Ports, welche eine solche Versionsvariable für jede einzelne Bibliothek, die sie erzeugen, benutzen.

Libtool-basierte Ports kann man am besten verarbeiten, wenn USE_LIBTOOL=Yes gesetzt wurde. Hiermit wird die Portstree-Version von libtool aktiviert, wodurch die meisten Details automatisch abgearbeitet werden:

Versuche alle, vom Benutzer sichtbaren, Bibliotheken in /usr/local/lib abzulegen

Als Regel gilt, dass das Beauftragen des Benutzers, Verzeichnisse zu ihrem ldconfig-Pfad anzuhängen, eine schlechte Idee ist: alle Shared Librarys, die direkt zu Programmen verlinkt sind, sollten in /usr/local/lib auftauchen. Trotzdem ist es möglich, einen symbolischen Link zur tatsächlichen Bibliothek zu verwenden. Du solltest die Bibliotheks-,lookup'-Regeln verstehen: So, lass uns annehmen, du hast zwei Ports, die zwei Hauptversionen einer gegebenen Bibliothek anbieten, sagen wir qt.1.45 und qt.2.21. Da beide Ports gleichzeitig installiert werden können, stelle sicher, dass ein gegebenes Programm gegen qt.1-Bibliothek gelinkt wird, welche als /usr/local/lib/qt/libqt.so.1.45 vorliegt, und Programme unter Verwendung von ld -o program program.o -L/usr/local/lib/qt -lqt gelinkt werden. Ähnlich soll ein Programm, das mit qt.2 linkt, die /usr/local/lib/qt2/libqt.so.2.31-Datei nutzen und mit ld -o program program.o -L/usr/local/lib/qt2 -lqt gelinkt werden.

Um diese Bibliotheken zur Laufzeit aufzulösen, wurden eine Verknüpfung mit dem Namen /usr/local/lib/libqt.so.1.45 und eine Verknüpfung namens /usr/local/lib/libqt.so.2.31 bereitgestellt. Dies ist genug, um ld.so glücklich zu machen.

Es ist ein Fehler, ein Programm unter Verwendung von qt1 mit ld -o program program.o -L/usr/local/lib -lqt zu linken. Dieser Code nimmt an, dass qt.2.21 nicht installiert sei, was eine Fehlannahme ist.

Solche Tricks sind nur notwendig, wenn der seltene Fall von sehr weitverbreiteten Bibliotheken vorliegt, bei denen Übergangszeiten zwischen Hauptversionen bereitgestellt werden müssen. Generell gilt, dass es genug ist, sicherzustellen, dass eine Bibliothek in /usr/local/lib auftaucht.

Bibliotheksabhängigkeiten richtig schreiben

Der neue Abhängigkeitscode (dependency code) benötigt nicht komplette Bibliotheksabhängigkeiten. Du musst make lib-depends-check verwenden, um sicherzustellen, dass ein Port alle Bibliotheken angibt, auf die er aufbaut. Du trennst Bibliotheksangaben mit Kommata, wie hier: LIB_DEPENDS=gtk.1.2,gdk.1.2::x11/gtk+.

Es ist kein Fehler, statische Bibliotheken in einer LIB_DEPENDS-Zeile ebenfalls anzugeben. LIB_DEPENDS werden während der Erzeugungsphase des Packages vollständig verarbeitet: das resultierende Package wird eine Bibliotheksabhängigkeitsinformation als Zeilen für ld.so eingebettet haben, die die tatsächliche Haupt.Unter-Nummer beinhalten, die beim Erzeugen verwendet wurden und keine Einträge für statische Bibliotheken.

Du musst ebenfalls RUN_DEPENDS bereitstellen, wenn ein Ports irgendetwas ordentlich benötigt, das über Bibliotheken hinausgeht. Das erlaubt dem Port auf Architekturen ordnungsgemäß erzeugt werden zu können, die keine Shared Librarys bereitstellen.

In der Tat ist das Bereitstellen einer LIB_DEPENDS-Zeile für statische Bibliotheken eine gute Idee: das vereinfacht einen Portupgrade, wenn eine gegebene Abhängigkeit von einer statischen Bibliothek zu einer Shared Library wechselt.

LIB_DEPENDS-Zeilen müssen die gleichen Pfade angeben, die für ld genutzt werden. Zum Beispiel basiert das standardmäßige qt2 auf einem Fragment, das sagt: LIB_DEPENDS+=lib/qt2/qt.2::x11/qt2, sodass die Bibliotheksabhängigkeitszeile korrekt aufgelöst wird. Dies erlaubt dem Abhängigkeitsüberprüfungscode das richtige zu tun, wenn er mehreren Versionen der gleichen Bibliothek begegnet.

Ports korrekt aktualisieren

So, wenn du einen Port aktualisierst oder hinzufügst, der Shared Librarys benötigt, müssen einige Details richtig durchgeführt werden.
OpenBSD www@openbsd.org
$OpenBSD: libraries.html,v 1.10 2008/03/09 13:37:14 tobias Exp $