Schnellkurs in Sachen Libraries

aus PUG, der Penguin User Group
Wechseln zu: Navigation, Suche

Was sind Libs

Sinn und Zweck von Librarys ist es häufig gebrauchten Programm-Code nicht jedes mal neu erfinden zu müssen. Die wohl bekannteste ist die libc, in dieser liegen z.B alle Funktionen, um Dateien zu manipulieren oder um mit Daten über das Netz zu schicken, kurzum alles um mit dem Kernel zu interagieren.

Zu jeder Lib gehört auch noch ein Headerfile. In dem Headerfile steht, wie man diese Funktionen aus der Lib benutzen kann.

Zusammenfassend kann man sagen:

  • In einem Headerfile (.h) steht der Funktionsaufrufes drin.
  • In der Library der eigentlich auszuführende Code.


Welche Arten von Librarys gibt es

Es gibt zwei Arten von Libs das eine sind statische und das andere Shared Libs. Bei Linux haben die ersten .a als Endung und die anderen .so.


Statische Libs

Eine statische Lib wird beim Linken (dazu kommen wir später) einfach in Programm eingefügt. Das heißt jedes Programm das gegen eine statische Lib gelinkt wird, hat im eigenen Programm-Code die Funktionen der Lib enthalten. Warum das für die meisten Bereiche keine gute Idee ist, läßt sich ganz gut errechnen. Man nehme eine statische Lib mit einem halben MB Größe, dann sagen wir 30 Programme benuzten sie. Sind allein schein 15 MB unnötiger Platz. Trotzdem reichen statische Libs damit ein OS funktioniert, aber dann wird doch alles ziemlich groß und verbraucht massiv Speicher. Deswegen gibt es noch eine zweite Klasse von Libs.


Shared Libs

Eine Shared Lib wird nur einmal in den Speicher geladen, und dann von den Programmen die sie brauchen gemeinsam genutzt. Z.B wird nur einmal libqt für die KDE geladen. Und alle k* Applikationen greifen dann auf diese eine Version zu. Diese Art von Libs ist auch diejenige die beim Übersetzen und starten von Programmen am meisten Ärger macht. Wenn man sich aber mal die Ausgabe von top ansieht und den Speicher vor shrd oder unter SHARE betrachtet, sieht man, daß sich der Aufwand lohnt.


Wie findet Linux die Libs

Eigentlich ist das System ganz einfach. Der Teil der für das Laden von Libs zuständig ist (ld.so/ld-linux.so) sieht als erstes in der Umgebungs-Variable LD_LIBRARY_PATH nach. Und sucht in diesen Verzeichnissen nach den benötigten Libs. Dann werden die in /etc/ld.so.conf genannten Verzeichnisse durchsucht. Neue Einträge dort werden aber erst nach Ausführen von /sbin/ldconfig aktiv. Und zuletzt wird auch noch in /lib und /usr/lib gesucht. Wenn er jetzt die Lib noch nicht gefunden hat, gibt es ein »Error in loading...«.


Was macht der GCC eigentlich

Der GNU C-Compiler nimm den Source eines Programmes und erstellt daraus ein Object-File mit der Endung .o. Ein Object-File besteht im großen und ganzen aus dem fertigen Assemblercode und Angaben darüber wo dieser in dem File zu finden ist. Der gcc braucht zum Übersetzen der Programme nur die Headerfiles der Libs, nicht aber die Libs selber. Wenn er sein Object-File erstellt hat, ruft er den Linker ld auf, es sei den man hat es im mit der -c oder -E oder -S Option verboten.


Was macht der LD eigentlich

Der Linker ld nimmt die Object-Files und macht aus ihnen entweder ausführbare Programme oder Shared Librarys. Ausführbare Programme erzeugt er, in dem er alle daran beteiligten .o Files zusammenfasst und alle wichtigen Informationen über benutzte Shared Librarys dazuwirft, oder wenn ld mit der Option -static aufgerufen wird, erzeugt er ein statisch gelinktes Programm. D.h. Es werden die statischen Versionen der Libs genommen und in das Programm mit reingelinkt. Wen es interessiert kann sich ja mal ein Programm mit objdump -x ansehen, da steht z.B in der Dynamic Section welche Libs gebraucht werden. Wie ld genau Shared Librarys erzeugt ist nicht so wichtig.


Warum will er aber genau die Library

Wenn ein Programmierer einer Lib die Parameter für einen Funktionsaufruf ändernt, laufen nach Austausch der Lib auf einen System die Programme, die gegen die alte Version gelinkt waren, natürlich nicht mehr. Also ändert er die Version seiner Lib, sie heißt dann nicht mehr libfoo.so.1 sondern libfoo.so.2. Prinzipiell eine gute Sache. Nur was passiert beim Starten von Programmen die gegen eine alte Lib gelinkt sind?

Beim Linken schreibt der ld in ein Programm die Namen der Libs die das Programm zum laufen benötigt. Wenn man ld mit -lfoo aufruft wird in das Programm als benötigte Library einfach libfoo.so reingeschrieben. Das ist aber ziemlich ungünstig. Wir linken unser Programm also gegen libfoo.so. Wir haben in /usr/lib einen Link von libfoo.so nach libfoo.so.1. Beim starten des Programmes wird also immer der symbolische Link von libfoo.so nach libfoo.so.1 aufgelöst und dann die Lib geladen. Eine Woche später kommen wir auf die Idee eine neue Version von libfoo zu installieren. Also libfoo.so.2 in /usr/lib und den Link von libfoo.so darauf umbiegen. Und schon werden alle neu Programme dagegen gelinkt. Jetzt starten wir aber unser altes Programm das noch gegen libfoo.so.1 gelinkt war und boing fällt es auf die Nase, da sich die Lib zu stark geändert hat. Nun ist guter Rat teuer (Außer man ist M$, da gehört das so). Also haben SL noch das Feature soname. Beim erzeugen der SL bekommen sie einen soname verpasst. Bei unseren Beispiel würden wir libfoo.so den soname libfoo.so.1 verpassen. Wenn man jetzt ein Programm gegen diese SL linkt kommt als benötigte SL nicht mehr libfoo.so rein, sondern libfoo.so.1. Tata, hiermit ist unser Problem gelöst. Neue Programme werden jetzt immernoch automatisch gegen die neue Version gelinkt, und alte Programme finden auch ihre alte Version der SL. Das kann man auch noch ein wenig tiefer Staffeln, aber das Prinzip bleibt das selbe.

Eine weiter möglichkeit beim Linken zu beeinflussen welche Libs geladen werden ist die Option -rpath, damit kann man in dem Programm den Pfad in dem zuerst nach libs sucht eintragen. Dann wird bei starten der Programme erst in den Verzeichnissen die mit rpath angegeben wurden gesucht, und dann nach der oben angegebenen Reihenfolge.