Jetzt, nachdem die Software richtig konfiguriert wurde, muss sie nur noch kompiliert werden. Diese Phase ist normalerweise sehr einfach und beinhaltet keine ernsthaften Probleme.
Das bevorzugte Werkzeug der freien Software-Gemeinde für das Durchbauen von Quellcode ist make. Es hat zwei Vorteile:
Die auszuführenden Aktionen zum Durchbauen des Quellcodes sind in einer Datei mit namens Makefile oder GNUMakefile gespeichert. Wenn der Befehl make aufgerufen wird, liest er diese Datei – wenn sie im aktuellen Verzeichnis existiert. Falls nicht, kann die Datei mittels der make-Option -f spezifiziert werden.
make arbeitet unter Berücksichtigung eines Systems von Abhängigkeiten. Also besteht die Kompilierung einer Binärdatei (eines „ Target “) aus dem Abarbeiten mehrerer Phasen („Abhängigkeiten“). Um beispielsweise die (imaginäre) Binärdatei glloq zu erstellen, müssen die Objektdateien main.o und init.o (Zwischenstufen der Kompilierung) kompiliert und danach verbunden werden. Diese Objektdateien sind ebenfalls Targets, deren Abhängigkeiten in den entsprechenden Quellcode-Dateien bestehen.
Dieses Dokument ist nur eine kurze Einführung zum Überleben in der gnadenlosen Welt von make. Eine umfassende Dokumentation finden Sie in Managing Projects with Make, 2. Ausgabe, O'Reilly, von und .
Im Allgemeinen folgt die Benutzung von make mehreren Konventionen. Beispiele:
Ohne Argument führt make nur die Kompilierung des Programms ohne anschließende Installation aus.
Der Befehl make install bewirkt die Kompilierung des Programms (aber nicht immer) und die anschließende Installation der benötigten Dateien an den richtigen Stellen des Dateisystems. Manche Dateien werden nicht immer korrekt installiert (man, info) und müssen vom Benutzer selbst an die entsprechenden Stellen kopiert werden. Manchmal muss make install nochmals in Unterverzeichnissen durchgeführt werden. Das ist gewöhnlich bei Software von Drittanbietern der Fall.
Der Befehl make clean entfernt alle temporären Dateien, die während der Kompilierung erstellt wurden, sowie in den meisten Fällen auch die ausführbare Datei.
Der erste Schritt ist die Kompilierung des Programms, also (für eine imaginäres Beispiel):
$ make gcc -c glloq.c -o glloq.o gcc -c init.c -o init.o gcc -c main.c -o main.o gcc -lgtk -lgdk -lglib -lXext -lX11 -lm glloq.o init.o main.o -o glloq |
Gut, die Binärdatei wurde korrekt erstellt. Wir können also zum nächsten Schritt übergehen: die Installation der Dateien des Programm-Pakets (Binärdateien, Datendateien, usw.). Siehe „Installation“.
Wenn Sie neugierig genug sind, sich näher mit dem Makefile zu beschäftigen, werden Sie darin sowohl bekannte Befehle (rm, mv, cp, usw.) als auch ungewohnte Ausdrücke, wie z.B. $(CFLAGS), finden.
Das sind Variablen, die gewöhnlich am Anfang der Datei Makefile definiert werden und denen später ein entsprechender Wert zugewiesen wird. Variablen sind sehr hilfreich, wenn Sie die gleichen Optionen mehrfach hintereinander benutzen wollen.
Zur Ausgabe der Zeichenfolge „foo“ auf dem Bildschirm unter Verwendung von make all schreibt man:
TEST = foo all: echo $(TEST) |
In den meisten Fällen werden folgende Variablen gesetzt:
CC: Der Compiler. Normalerweise ist das cc, in den meisten Systemen ein Synonym für gcc. Im Zweifelsfall sollten Sie hier gcc einsetzen.
LD: Das Programm, das in der letzten Kompilierungsphase eingesetzt wird (siehe „In vier Schritten zum Programm“). Standardmäßig ist das ld.
CFLAGS: Die zusätzlichen Argumente, die dem Compiler in den ersten Kompilierungsphasen übergeben werden. Dazu gehören u.A.:
-I<path>: Informiert den Compiler, wo er nach zusätzlichen Header-Dateien suchen soll (beispielsweise bewirkt -I/usr/X11R6/include die Integration der Header-Dateien im Verzeichnis /usr/X11R6/include).
-D<symbol>: Definiert ein zusätzliches Symbol, hilfreich für Programme, deren Kompilierung von definierten Symbolen abhängt (Beispiel: die Datei string.h wird durch HAVE_STRING_H eingebunden).
Oft sieht man bei der Kompilierung Zeilen wie die folgende:
$(CC) $(CFLAGS) -c foo.c -o foo.o |
LDFLAGS (oder LFLAGS): Diese Argumente werden im letzten Schritt der Kompilierung verwendet. Dazu gehören (u.A.):
Keine Panik! Das kann Jedem passieren. Die am häufigsten auftretenden Gründe:
glloq.c:16: decl.h: No such file or directory
Der Compiler konnte die entsprechende Header-Datei nicht finden. Eigentlich hätte dieser Fehler bereits bei der Konfiguration auftreten sollen. Die Lösung des Problems:
Prüfen Sie, ob die Header-Datei in einem der folgenden Verzeichnisse existiert: /usr/include, /usr/local/include, /usr/X11R6/include oder in einem ihrer Unterverzeichnisse. Falls nicht, suchen Sie die Datei auf der gesamten Festplatte (benutzen Sie dazu find oder locate). Falls sie auch jetzt nicht gefunden wird, prüfen Sie, ob die entsprechende Bibliothek installiert ist. Beispiele für die Anwendung von find und locate finden Sie in den entsprechenden Handbuchauszügen.
Prüfen Sie, ob die Header-Datei auch lesbar für den Compiler ist (testen Sie das mit dem Befehl less <path>/<file>.h ).
Falls sich die Datei in einem Verzeichnis wie /usr/local/include oder /usr/X11R6/include befindet, muss man dem Compiler manchmal ein neues Argument übergeben. Öffnen Sie dazu die entsprechende Datei Makefile mit Ihrem bevorzugten Editor, z.B. Emacs, Vi, usw. (beachten Sie, dass Sie die richtige Datei öffnen, nämlich die Datei in dem Verzeichnis, in dem die Kompilierung fehlschlug[33]). Suchen Sie die fehlerhafte Zeile und fügen Sie die Zeichenkette -I<path> hinter dem Aufruf des Compilers (gcc oder manchmal auch $(CC)) ein, wobei <path> der Pfad zum Verzeichnis ist, in dem die gesuchte Header-Datei liegt. Falls Sie nicht wissen, wo Sie diese Option einfügen sollen, stellen Sie sie an den Anfang der Datei, direkt hinter die Zeilen CFLAGS=<irgendwas> oder CC=<irgendwas>.
Starten Sie make erneut. Falls es immer noch nicht funktioniert, prüfen Sie, ob diese Option (siehe letzter Absatz) während der Kompilierung in der fehlerhaften Zeile hinzugefügt wurde.
Wenn sich jetzt immer noch kein Erfolg einstellt, suchen Sie Hilfe bei Ihrem örtlichen GNU/Linux-Guru oder bei der Gemeinschaft der Nutzer freier Software (siehe „Technische Unterstützung“).
glloq.c:28: `struct foo' undeclared (first use this function)
In der Struktur werden spezielle Datentypen verwendet, die von allen Programmen benutzt werden. Viele davon werden vom System in Header-Dateien definiert. Das bedeutet, dass das Problem höchstwahrscheinlich durch eine fehlende oder falsch benutzte Header-Datei verursacht wird. Die korrekte Vorgehensweise zur Lösung dieses Problems ist:
Versuchen Sie festzustellen, ob der in Frage kommende Konstrukt vom Programm selbst oder vom System definiert wird. Dabei hilft Ihnen der Befehl grep, mit dem Sie die Header-Dateien durchsuchen können.
Angenommen, Sie befinden sich im Hauptverzeichnis des Programm-Paketes:
$ find . -name '*.h'| xargs grep 'struct foo' | less |
Daraufhin können unter Umständen sehr viele Zeilen auf dem Bildschirm erscheinen (etwa eine Zeile für jedes Mal, bei dem eine Funktion definiert wird, die den Konstrukt benutzt). Sehen Sie sich die Header-Dateien an, die Ihnen grep als Resultat liefert und suchen Sie – falls sie existiert – die Zeile, in der der Konstrukt definiert wird.
Die Definition eines solchen Konstrukts sieht so aus:
struct foo { <inhalt des konstrukts> }; |
Prüfen Sie, ob die Zeile dem entspricht, was Sie suchen. Falls ja, bedeutet das, dass die Header-Datei nicht in der defekten .c-Datei genannt wird. Für diesen Fall gibt es zwei Lösungen:
Wenn Sie die gesuchte Stelle nicht finden, setzen Sie die Suche in gleicher Weise bei den System-Header-Dateien fort (die im Allgemeinen in den Verzeichnissen /usr/include, /usr/X11R6/include oder /usr/local/include liegen). Dabei benutzen Sie als Suchkriterium jetzt die Zeile #include <<filename>.h>.
Falls dieser Konstrukt auch an diesen Stellen nicht existiert, so versuchen Sie herauszufinden, in welcher Bibliothek (d.h., in welcher Funktionen-Sammlung) er definiert werden sollte (in den Dateien INSTALL oder README sehen Sie, welche Bibliotheken in welchen Versionen vom Programm benutzt werden). Falls die vom Programm benötigte Version nicht auf Ihrem System installiert ist, müssen Sie sie installieren.
Falls Sie damit auch keinen Erfolg haben, stellen Sie fest, ob das Programm überhaupt auf der von Ihnen benutzten Architektur lauffähig ist. Einige Programme wurden noch nicht auf alle UNIX®-Systeme portiert. Prüfen Sie nochmals nach, ob Sie während der Konfiguration (configure) das Programm richtig für die von Ihnen benutzte Architektur eingerichtet haben.
Dieses Problem ist schwer zu lösen, da es oft durch eine bestimmte Zeile ausgelöst wird, nachdem der Compiler diese Zeile wieder verlassen hat. Manchmal liegt es einfach an einem nicht definierten Datentyp. Wenn Sie eine Fehlermeldung wie diese erhalten:
main.c:1: parse error before `glloq_t main.c:1: warning: data definition has no type or storage class |
besteht das Problem darin, dass der Datentyp glloq_t nicht definiert wurde. Die Lösung dieses Problems gleicht mehr oder weniger der Lösung des vorangegangenen Problems.
(Deutsch: „Kein Platz mehr auf dem Gerät verfügbar“). Dieses Problem kann leicht gelöst werden: es besteht darin, dass auf der Festplatte kein ausreichender freier Platz zur Erzeugung der Binärdatei vorhanden ist. Die Lösung ist: schaffen Sie freien Platz auf der Partition, die das Installationsverzeichnis enthält (löschen Sie temporäre Dateien oder Quellcodes, de-installieren Sie Programme, die Sie nicht benutzen, usw., falls Sie das Programm-Paket in /tmp entpackt haben, anstatt /usr/local/src zu benutzen, was eine unnötige Unordnung auf der /tmp-Partition vermeidet. Prüfen Sie, ob es auf Ihrer Festplatte core-Dateien[34] gibt. Wenn ja, löschen Sie sie oder veranlassen Sie die Löschung, falls die Dateien einem anderen Benutzer gehören.
/usr/bin/ld: cannot open -lglloq: No such file or directory
Das bedeutet klar und deutlich, dass das Programm ld (aufgerufen von gcc während der letzten Phase der Durchbauens) eine Bibliothek nicht finden kann. Zum Einbinden einer Bibliothek sucht ld nach einer Datei, deren Name in den Argumenten des Typs -l<library> genannt wird. Diese Datei ist lib<library>.so. Wenn ld sie nicht finden kann, wird eine Fehlermeldung erzeugt. Das Problem kann mit den folgenden Maßnahmen beseitigt werden:
Vergewissern Sie sich mit dem Befehl locate, dass die Datei auf Ihrer Festplatte vorhanden ist. Normalerweise liegen die grafischen Bibliotheken im Verzeichnis /usr/X11R6/lib. Ein Beispiel für die Suche:
$ locate libglloq |
Wenn diese Suche erfolglos ist, versuchen Sie es mit dem Programm find (etwa: find /usr -name "libglloq.so*"). Falls das auch kein Resultat bringt müssen Sie die Bibliothek installieren.
Wenn die Bibliothek gefunden wird, prüfen Sie nach, ob sie von dem Befehl ld gelesen werden kann: die Datei /etc/ld.so.conf spezifiziert die Verzeichnisse, in denen diese Bibliotheken liegen. Fügen Sie das bei der Suche gefundene Verzeichnis am Ende der Datei hinzu (möglicherweise müssen Sie danach Ihren Rechner neu starten um dem System die Änderung bekannt zu machen). Sie können das Verzeichnis auch in die Umgebungsvariable LD_LIBRARY_PATH integrieren. Wenn das gefundene Verzeichnis beispielsweise /usr/X11R6/lib heißt, geben Sie ein:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/X11R6/lib |
Wenn Sie jetzt immer noch keinen Erfolg haben, prüfen Sie mit dem Kommando file ob die Bibliothek eine ausführbare Datei ist (oder ELF). Falls es ein symbolischer Link ist prüfen Sie, ob der Link korrekt ist und auf eine existierende Datei zeigt (mit dem Befehl nm libglloq.so beispielsweise). Auch die Berechtigungen können falsch gesetzt sein (wenn Sie nicht den root-Account benutzen und die Bibliothek beispielsweise gegen das Lesen geschützt ist).
glloq.c(.text+0x34): undefined reference to `glloq_init'
Dies ist ein durch ein Symbol verursachtes Problem, das während der letzten Kompilierungsphase nicht gelöst wurde. Normalerweise ist das ein Bibliotheken-Problem für das es mehrere mögliche Gründe geben kann:
Das Erste, was man hier machen sollte, ist herauszufinden, ob das Symbol normalerweise in eine Bibliothek gehört. Wenn es zum Beispiel ein Symbol ist, dessen Name mit gtk beginnt, so gehört es in eine gtk-Bibliothek. Wenn der Name der in Frage kommenden Bibliothek so einfach zu identifizieren ist wie z.B. frobnicate_foobar, können Sie die Symbole der Bibliothek mit dem Befehl nm auflisten:
$ nm libglloq.so 0000000000109df0 d glloq_message_func 000000000010a984 b glloq_msg 0000000000008a58 t glloq_nearest_pow 0000000000109dd8 d glloq_free_list 0000000000109cf8 d glloq_mem_chunk |
Mit der Option -o des Befehls nm wird der Name der Bibliothek in jeder Zeile angezeigt, was die Suche sehr erleichtert. Angenommen, wir suchen das Symbol bulgroz_max, so kann eine simple Lösung so aussehen:
$ nm /usr/lib/lib*.so | grep bulgroz_max $ nm /usr/X11R6/lib/lib*.so | grep bulgroz_max $ nm /usr/local/lib/lib*.so | grep bulgroz_max /usr/local/lib/libfrobnicate.so:000000000004d848 T bulgroz_max |
Wunderbar! Das Symbol bulgroz_max wird in der Bibliothek frobnicate definiert (der Großbuchstabe T steht vor dem Namen). Nun brauchen Sie nur die Zeichenfolge -lfrobnicate in die Zeile des Makefiles einzufügen: hängen Sie sie an das Ende der Zeile, in der LDFLAGS oder LFGLAGS (oder im Schlimmsten Fall CC) definiert werden, oder an die Zeile, die die endgültige Binärdatei erstellt.
Die Kompilierung der Software wurde mit einer Version der Bibliothek versucht, die für diese Software nicht zugelassen ist. In der Datei README oder INSTALL des Programm-Pakets sehen Sie, welche Version benutzt werden muss.
Es wurden nicht alle Objekt-Dateien des Programm-Pakets sauber eingebunden. Es fehlt die Datei, in der diese Funktion definiert wird. Geben Sie nm -o *.o ein und prüfen Sie, welche Datei fehlt. Fügen Sie die entsprechende .o-Datei in die Kompilierungszeile ein, falls sie dort fehlt.
Die problematische Funktion oder Variable existiert möglicherweise nicht. Versuchen Sie, sie zu entfernen: editieren Sie dazu die entsprechende Quellcode-Datei, deren Name am Anfang der Fehlermeldung genannt wird. Dies ist eine verzweifelte Lösung, deren Konsequenz sehr wahrscheinlich in einem chaotischen Verhalten des Programms bestehen wird (etwa ein Speicherzugriffsfehler – segfault – beim Start, usw.).
Segmentation fault (core dumped)
Manchmal hängt der Compiler sofort nach Beginn und gibt diese Fehlermeldung aus. Dazu habe ich keinen Rat ausßer dem Vorschlag, eine neuere Version des Compilers zu installieren.
Die Kompilierung benötigt temporären freien Platz während der verschiedenen Phasen. Ist dieser nicht vorhanden so misslingt das Vorhaben. Also sollten Sie die Partition säubern. Aber beachten Sie dabei, dass einige laufende Programme (X-Server, Pipes, etc) durch das entfernen benötigter Dateien abgebrochen werden können. Sie müssen also genau wissen, was Sie tun! Falls /tmp nicht auf einer eigenen Partition liegt (beispielsweise auf der Root-Partition) können Sie eventuell vorhandene core-Dateien suchen und entfernen.
make/configure in unendlicher Wiederholung
Oft besteht das Problem in der Zeit des Systems. make muss tatsächlich die Zeit des Rechners kennen sowie die Zeitstempel der benötigten Dateien. Es vergleicht die Zeitstempel und weiß durch das Resultat, ob etwa das Target jünger als die abhängige Datei ist.
Ein paar Zeitprobleme können make dazu bringen, sich endlos immer wieder neu zu erstellen (oder Unterverzeichnisse in unendliche Wiederholung anzulegen). In solch einem Fall ist touch die Lösung. Man gibt damit den entsprechenden Dateien den aktuellen Zeitstempel, womit normalerweise das Problem gelöst ist.
$ touch * |
Oder auch (simpel, aber wirksam):
$ find . | xargs touch |
[33] Sehen Sie sich die Fehlermeldung von make genau an. Normalerweise enthalten die letzten Zeilen den Namen eines Verzeichnisses (z.B.: make[1]: Leaving directory `/home/franz/Project/foo'). Wählen Sie das Verzeichnis in der Zeile mit der höchsten Nummer. Prüfen Sie, ob Sie das richtige Verzeichnis gewählt haben, durch einen erneuten Aufruf von make in diesem Verzeichnis. Es sollte die gleiche Fehlermeldung erscheinen.
[34] Dateien, die vom System erzeugt werden, wenn ein Prozess einen Speicherbereich belegen will, den er nicht belegen darf. Diese Dateien werden dazu verwendet, den Grund des falschen Verhaltens zu finden und den Fehler zu beseitigen.