21Bibliotheken, Java und Mono

Im Mittelpunkt dieses Kapitels stehen Bibliotheken, die zur Ausführung von Programmen erforderlich sind. Die meisten Linux-Programme stehen in kompilierter Form zur Verfügung und greifen auf diverse Bibliotheken zurück, die dynamisch bei Bedarf geladen werden. Der erste Abschnitt dieses Kapitels führt in die unter Linux übliche Bibliotheksverwaltung ein.

Wenn Sie mit gängigen Distributionen arbeiten, installieren Sie zumeist nur fertig kompilierte Programme in Form von sogenannten Binärpaketen. Wenn Sie allerdings ganz neue Programmversionen oder selten benutzte Programme einsetzen möchten, kann es sein, dass Sie keine vorkompilierte Version des Programms zum Download finden. In solchen Fällen müssen Sie den Quellcode (meist in den Sprachen C oder C++) herunterladen und das Programm selbst kompilieren. Abschnitt 21.2 gibt dazu einige einführende Tipps, ohne aber im Detail auf das unerschöpfliche Thema Programmentwicklung unter Linux einzugehen.

Das Kapitel beschreibt auch, wie unter Linux Java- bzw. .NET-Programme ausgeführt werden. Dazu muss eine Java-Laufzeitumgebung bzw. Mono installiert werden. Bei vielen Distributionen ist das standardmäßig der Fall.

Scripts, die von einem Interpreter ausgeführt werden, sind nicht Thema dieses Kapitels. Unter Linux sind diverse Script-Sprachen üblich, unter anderem Perl, Python, PHP sowie die Shell bash. Dieses Buch geht allerdings nur auf die bash ausführlich ein (siehe Kapitel 12).

21.1Bibliotheken

Praktisch alle Linux-Programme verwenden dieselben Standardfunktionen, beispielsweise zum Zugriff auf Dateien, zur Ausgabe am Bildschirm, zur Unterstützung von X etc. Es wäre sinnlos, wenn jedes noch so kleine Programm all diese Funktionen unmittelbar im Code enthalten würde – riesige Programmdateien wären die Folge. Stattdessen bauen die meisten Linux-Programme auf sogenannten Shared Libraries auf: Bei der Ausführung eines Programms werden automatisch die erforderlichen Bibliotheken geladen. Der Vorteil: Wenn mehrere Programme Funktionen derselben Bibliothek nutzen, muss die Bibliothek nur einmal geladen werden.

Bibliotheken spielen eine zentrale Rolle dabei, ob und welche Programme auf Ihrem Rechner ausgeführt werden können. Fehlt auch nur eine einzige Bibliothek bzw. steht sie in einer zu alten Version zur Verfügung, kommt es beim Programmstart zu einer Fehlermeldung. Damit Sie in solchen Fällen nicht ganz hilflos den Tiefen der Linux-Interna ausgeliefert sind, vermittelt dieser Abschnitt einige Grundlageninformationen zu Bibliotheken.

Zu den wichtigsten und grundlegendsten Linux-Bibliotheken zählt die GNU C Library (glibc), die mitunter auch als libc 6 bezeichnet wird. Im Sommer 2015 lag die glibc in der Version 2.22 vor. Normalerweise gibt es pro Jahr zwei bis drei Versions-Updates.

Gewöhnliche Programme greifen wie oben beschrieben auf Bibliotheken zurück. Diese Bibliotheken werden erst zur Laufzeit dynamisch geladen und sind vom Konzept her mit Windows-DLLs (Dynamic Link Libraries) zu vergleichen.

Beim Kompilieren eines Programms besteht auch die Möglichkeit, Libraries statisch zu linken. Das bedeutet, dass die Library-Funktionen direkt in den Programmcode integriert werden. Die Programmdatei wird dadurch größer, ist aber nicht mehr von irgendwelchen Libraries abhängig. Das ist praktisch, um Programme unkompliziert weiterzugeben.

Bibliotheken automatisch laden

Sofern Sie Linux als Anwender und nicht als Programmierer nutzen, werden Sie mit Bibliotheken nur dann konfrontiert, wenn diese fehlen. Meistens treten solche Probleme auf, wenn Sie manuell, also ohne Paketverwaltungswerkzeuge, ein neues Programm installieren. Beim Versuch, das Programm zu starten, erscheint eine Fehlermeldung, in der das Fehlen einer bestimmten Library angezeigt wird.

Dem Kommando ldd wird als Parameter der vollständige Dateiname des Programms übergeben. Als Reaktion listet ldd alle Libraries auf, die das Programm benötigt. Außerdem wird angegeben, wo sich eine passende Library befindet und welche Libraries fehlen bzw. nur in einer veralteten Version zur Verfügung stehen.

user$ ldd /bin/cp linux-vdso.so.1 (0x00007fff443e0000) libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fab67006000) libacl.so.1 => /lib64/libacl.so.1 (0x00007fab66dfd000) libattr.so.1 => /lib64/libattr.so.1 (0x00007fab66bf7000) libc.so.6 => /lib64/libc.so.6 (0x00007fab6682b000) libpcre.so.1 => /lib64/libpcre.so.1 (0x00007fab665bb000) libdl.so.2 => /lib64/libdl.so.2 (0x00007fab663b6000) /lib64/ld-linux-x86-64.so.2 (0x000055e912eb1000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fab66198000)

Bei X-, KDE- und Gnome-Programmen ist die Bibliotheksliste wesentlich länger. Das ist auch der Grund, warum der Start dieser Programme relativ lange dauert. Wenn ldd hingegen das Ergebnis not a dynamic executable liefert, handelt es sich um ein Programm, das alle erforderlichen Bibliotheken bereits enthält, also um ein statisch gelinktes Programm.

Kurz einige Informationen zur Nomenklatur der Libraries: Das Kürzel .so weist darauf hin, dass es sich um eine Shared Library handelt (im Gegensatz zu .a für statische Libraries). Die folgende Ziffer gibt die Hauptversionsnummer an. cp benötigt also Version 6 der libc-Bibliothek.

In den Verzeichnissen /lib, /lib64, /usr/lib etc. befinden sich oft Links von der Hauptversion auf die tatsächlich installierte Version. So benötigt cp die Bibliothek ld-linux-x86-64 in der Version 2. Tatsächlich ist aber die dazu kompatible Version 2.21 installiert:

user$ ls -l /lib64/ld-* ... /lib64/ld-2.21.90.so ... /lib64/ld-linux-x86-64.so.2 -> ld-2.21.90.so

Beim Start eines Programms ist der sogenannte Runtime Linker ld.so dafür zuständig, alle Bibliotheken zu finden und zu laden. Dazu wertet der Linker die Datei /etc/ld.so.cache aus. Diese Binärdatei enthält alle relevanten Bibliotheksdaten, also Versionsnummern, Zugriffspfade etc. Der Zweck dieser Datei besteht darin, dem Linker eine langwierige Suche nach den Bibliotheken zu ersparen.

/etc/ld.so.cache wird vom Programm ldconfig erzeugt. ldconfig wertet seinerseits /etc/ld.so.conf aus. Diese Datei enthält eine Liste mit Pfadangaben bzw. Querverweise auf andere Konfigurationsdateien.

Die Verzeichnisse /lib und /usr/lib werden auf jeden Fall berücksichtigt und fehlen daher zumeist in ld.so.conf bzw. in den weiteren Konfigurationsdateien. Wenn außer /lib und /usr/lib keine weiteren Verzeichnisse zu berücksichtigen sind, kann ld.so.conf auch ganz fehlen.

Bei manchen Distributionen wird ldconfig bei jedem Rechnerneustart ausgeführt, um so sicherzustellen, dass die Cache-Datei auf dem aktuellsten Stand ist. ldconfig muss unbedingt ausgeführt werden, wenn neue Bibliotheken manuell installiert werden! Andernfalls sind die Bibliotheken für das System nicht sichtbar. Falls sich die Bibliotheken in einem neuen Verzeichnis befinden, muss außerdem die Datei /etc/ld.so.conf entsprechend ergänzt werden. Bei der Installation von Bibliothekspaketen kümmert sich in der Regel der Paketmanager um diese Aufgaben.

ld.so berücksichtigt zusätzlich alle in der Umgebungsvariablen LD_LIBRARY_PATH enthaltenen Verzeichnisse. Die Verzeichnisse müssen durch Doppelpunkte getrennt sein. Bei vielen Distributionen ist diese Umgebungsvariable leer.

32- und 64-Bit-Bibliotheken

Die meisten gängigen Distributionen gibt es momentan in zumindest zwei Ausführungen: für Intel/AMD-kompatible 32-Bit-Prozessoren und für Intel/AMD-kompatible 64-Bit-Prozessoren. Bei 32-Bit-Distributionen gibt es naturgemäß nur 32-Bit-Bibliotheken. Dies gilt aber leider nicht analog für 64-Bit-Distributionen: Nach wie vor gibt es Programme, die sich nicht für 64-Bit-Systeme kompilieren lassen.

Zur Ausführung von 32-Bit-Programmen auf 64-Bit-Distributionen sind 32-Bit-Bibliotheken erforderlich. Um Konflikte zu vermeiden, werden die Bibliotheken in unterschiedliche Verzeichnisse installiert. Im Linux-Jargon heißt diese Vorgehensweise Multi Architecture (Multiarch) bzw. exakter Bi-architecture, weil mehrere bzw. zwei Prozessorarchitekturen parallel unterstützt werden. Bei den meisten Distributionen sind die Verzeichnisse /lib und /lib64 üblich, um zwischen 32- und 64-Bit-Bibliotheken zu differenzieren. Diese Doppelgleisigkeit ist natürlich mit Nachteilen verbunden: Die doppelte Installation von Bibliotheken erfordert zusätzlichen Platz auf der Festplatte und macht die Wartung komplizierter.

Eine andere Lösung besteht darin, innerhalb von /usr/lib Unterverzeichnisse für die jeweilige CPU-Architektur zu schaffen, z.B. /usr/lib/x86_64-linux-gnu (Debian ab Version 7, Ubuntu ab Version 12.04). Der Vorteil dieses Ansatzes besteht darin, dass er über die Intel/AMD-Welt hinaus auch auf ganz andere CPU-Architekturen übertragbar ist.

Die Multiarch-Idee erstreckt sich über Verzeichnispfade hinweg auch auf die Paketverwaltung: Es muss zum Beispiel möglich sein, ein und dasselbe Paket bei Bedarf mehrfach zu installieren, einmal in der 32-Bit- und einmal in der 64-Bit-Version. Zur klareren Unterscheidung kann dem Paketnamen die Architektur mit einem Doppelpunkt angehängt werden, z.B. gvfs:i386 (bezeichnet die 32-Bit-Version des gvfs-Pakets). Auch die Abhängigkeitsüberprüfung muss nun doppelläufig arbeiten (also für 32- und 64-Bit-Abhängigkeiten). Das dpkg-Kommando unterstützt den Multiarch-Ansatz bereits gut.

Prelinking

Beim Start eines Programms, das auf dynamische Bibliotheken zurückgreift, muss eine Verbindung zwischen dem Programm und den Bibliotheken hergestellt werden.

Dieser Vorgang wird als Linking bezeichnet. Er beansprucht bei komplexen Programmen einige Zeit.

Das Programm prelink kann die erforderlichen Link-Informationen im Voraus ermitteln, was beim ersten Mal ebenfalls lange dauert. Bei diesem Vorgang müssen alle ausführbaren Programme durchsucht werden. Welche Verzeichnisse für Programme und Bibliotheken prelink berücksichtigt, wird durch die Datei /etc/prelink.conf konfiguriert. Weitere Optionen können Sie in /etc/sysconfig/prelink bzw. /etc/default/prelink (Debian, Ubuntu) einstellen.

In der Folge kann jedes so präparierte Programm schneller auf seine Bibliotheken zugreifen. Die Prelinking-Informationen müssen allerdings jedes Mal aktualisiert werden, wenn eine Bibliothek aktualisiert wird.

Prelinking ist allerdings auch mit diversen Nachteilen verbunden. Wegen der Veränderung ausführbarer Dateien ist es anschließend nicht mehr möglich, die Integrität dieser Dateien zu kontrollieren. Dieser und andere Gründe haben dazu geführt, dass Prelinking bei den meisten Distributionen nicht standardmäßig aktiv ist.

https://fedorahosted.org/fesco/ticket/1183

Um Prelinking unter Debian und Ubuntu zu nutzen, müssen Sie das Paket prelink installieren und in /etc/default/prelink die Einstellung PRELINKING=yes vornehmen. prelink wird täglich durch einen Cron-Job ausgeführt.

Bei aktuellen Fedora-Versionen steht Prelinking nicht mehr zur Verfügung.

Bei RHEL 6 und CentOS 6 ist Prelinking standardmäßig eingerichtet. Um Prelinking auch in Version 7 zu nutzen, müssen Sie das Paket prelink installieren. Die Prelinking-Informationen werden regelmäßig aktualisiert (Cron-Job /etc/cron.daily/prelink, Konfigurationsdatei /etc/sysconfig/prelink).

Um Prelinking in aktuellen SUSE-Distributionen zu nutzen, müssen Sie das Paket prelink installieren und das gleichnamige Kommando selbst ausführen. Ein automatischer Start ist nicht vorgesehen.