Software kompilieren

Von Robert

In der heutigen Zeit bekommt man schon viele Programme als Binaries, dass heißt sie müssen vom User nicht mehr selbst kompiliert werden, sondern liegen für die betreffende Linux Distribution in kompilierter Form vor. Aber jeder User wird im Laufe seiner Arbeit irgendwann einmal in die Situation kommen, ein Programm selber kompilieren zu müssen.

Zwar ist jede Distribution mit vielen Programmen ausgestattet, aber diese sind nicht immer auf dem neuesten Stand. Und wenn man diese nun alle immer aktuell halten möchte, wird man nicht drum herum kommen, sich mit dem Kompilieren zu beschäftigen und auseinanderzusetzen. Auch bei Exoten, wird man nicht am Kompilieren vorbeikommen, besonders wenn man sie auf nicht alltäglichen System wie Alpha/Linux einsetzen will.

Der Quelltext eines Programmes, auch Source Code genannt beinhaltet den unkompilierten Programm-Code, zum Beispiel im C-Format oder einem anderen. In vielen Source-Paketen, welche man im Internet findet sind des weiteren noch vorkompilierte Bibliotheken, Include / Header Dateien und Man-Pages enthalten.

Libraries oder auch Bibliotheken enthalten einen schon vorkompilieren Programmcode, der von anderen Programmen benutzt werden kann. Zum Beispiel benötigen alle C-Programme die libc Library und alle X11 Programme die libX11 Library.

Die Header Dateien teilen dem Compiler mit, welche Funktionen sich in der Bibliothek befinden und welche Parameter diese Funktion hat und was an sie übergeben wird. Es ist also eine Schnittstelle zwischen dem Programm und der Bibliothek.


Source Code

Hat man sich das gewünschte Source-Paket aus dem Internet runtergeladen, muss man es zuerst auf der Festplatte entpacken. Die meisten Pakete sind mit tar und dann mit gzip (oder bzip2) gepackt.
Zunächst sollte man sich den Inhalt des Archives ansehen, und prüfen, ob es sich in einem Unterverzeichnis befindet.

$ tar tvfz program-src.tar.gz

Falls die Sources in keinem eigenen Verzeichnis liegen, sollten wir vorher noch ein Verzeichnis anlegen und den Tar-Ball dorthin entpacken, wenn die Sources allerdings in einem eigenen Unterverzeichnis liegen kann man das Archiv entpacken, dies geschieht z.B. mit:

$ tar xvfz program-src.tar.gz


ReadMe, Konfiguration und Ablauf

Nachdem nun der Quelltext entpackt worden ist, muss der Quelltext so konfiguriert werden, das er sich kompilieren lässt. Dazu sollte man insbesondere die mitgelieferten ReadMe und Help Dateien lesen. Auch die Datei INSTALL enthält oft sehr wichtige Hinweise zur Vorgehensweise.

Eine Installation geschieht meistens nach folgenden Schritten:

(Makefile) - optional: Makefile von Hand bearbeiten.

./configure - Konfiguration, aller nötigen Einstellungen zur Installation und Erstellung das Makefile‘s.

make - make liest das Makefile aus, arbeitet es ab und kompiliert das Programm.

Root-Login - um den Befehl make install auszuführen, muss man sich nun als Root auf dem System einloggen.

make install - ist normalerweise dafür da, das fertige Programm und alle benötigten Dateien (z.B. configs und Man-Pages) zu installieren, sprich an ihren Bestimmungsort zu kopieren.

In den folgenden Abschnitten werden die einzelnen Punkte nun erläutert.


Makefile

In vielen älteren Source Versionen musste man das Makefile, welches in einer Grundform vorhanden war, von Hand an sein bestehendes System anpassen. In der heutigen Zeit wird dieses vom Configure-Script erledigt, aber dazu mehr im nächsten Abschnitt. Durch eine gute ReadMe, oder Kommentare im Makefile, wird es dem User ermöglicht, das Makefile an die vorhandenen Bedingungen anzupassen. Im folgenden wird ein kurzer Auszug dargestellt.

Listing 1: Auszug Makefile

# edit the following variables according to your need:

INCLUDE = /usr/local/include  	# Include Dateien
LIB     = /usr/local/lib	
DEST    = /usr/local/bin	# Destination Folder
MAN     = /usr/local/man	# Manual Folder

#######

CC = gcc  			# der zu nutzende Compiler
DEFINES = -DLINUX
CFLAGS = $ (DEFINES) -O2
LIBS = -1X11 -1m

Die Variable CC gibt an, welcher Compiler genutzt werden soll, unter den meisten Linux Distributionen ist es GCC (Gnu Compiler Collection) oder eine Weiterentwicklung wie egcs. Mit CFLAGS kann man Optionen an den C-Compiler übergeben.
Am häufigsten sind die Optionen -L und -I, mit ihrer Hilfe kann man dem Compiler mitteilen wo sich die (L)ibraries und die (I)nclude Dateien befinden, wenn diese sich in speziellen Verzeichnissen befinden.

Standardmäßig geht der gcc davon aus, das sich die Bibliotheken in /usr/lib oder /usr/local/lib befinden. Sollte dies auf ihrem System nicht zutreffen müssen sie mit der Option –L eine Anpassung vornehmen. Die Include Dateien befinden sich normalerweise in /usr/include oder /usr/local/include. Auch hier ist bei Abweichungen eine Anpassung nötig.


configure

Der Quelltext der meisten neueren Programme nutzt das Configure-Script, um das Makefile anzupassen, somit fällt die aufwendige Bearbeitung per Hand weg. Das Configure-Script prüft bei der Ausführung, um welches Betriebssystem es sich handelt, welche Bibliotheken nötig sind, und es wird das passende Makefile erstellt.

$ ./configure

Weiterhin kann man den Befehl configure mit vielen Optionen aufrufen, um das Makefile an die Userwünsche anzupassen. Mit der Option ./configure --help kann man sich alle verfügbaren Optionen des Configure-Scriptes ausgeben lassen, da sie sich doch öfters mal in der Syntax und der zu Verfügung stehenden Optionen unterscheiden. Die wohl am häufigsten genutzte Option ist --prefix, mit ihrer Hilfe kann man festlegen wohin ein Programm am Ende Installiert wird.

$ ./configure --prefix=/usr/local/program

Hier zum Beispiel der Pfad /usr/local/program. Das Programm wird nun unterhalb des Pfades /usr/local/program installiert. Will man das Programm später ins $HOME (z.B. /home/usr) Verzeichnis installieren, benötigt man im make install Schritt später auch kein Root-Login, dies kann man wie folgt erreichen ./configure ein --prefix=/~
Es kann aber auch passieren das configure mit einem Fehler abbricht, weil auf dem bestehenden System ein Programm oder eine Bibliothek nicht vorhanden ist. Ein typischer Fehler könnte so aussehen:

$ ./configure --prefix=/usr/local/program

checking for gcc... no
configure: error: no acceptable gcc found in $PATH

Dieser Fehler lässt darauf schließen, das auf dem System kein gcc Compiler installiert ist. Um nun Programme kompilieren zu können ist dieser zwingend notwendig. Eine weitere Fehlerquelle ist das Nichtvorhandensein von Bibliotheken, oder das Fehlen von Include-Datein. Wenn man alle Fehlerquellen im Configure-Script abgearbeitet hat, und es fehlerfrei durchläuft, sollte es ähnlich diesem aussehen.

$ ./configure --prefix=/usr/local/program

checking for gcc... gcc
checking for C compiler default output... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
.......
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h

Configure is done.

Mit dem fehlerfreien Durchlaufen von configure, wurde nun auch ein Makefile erstellt.

Listing 2: Makefile vom Configure-Script erstellt

#  This is the Makefile for program
#  You should never need to edit this.
#
# $Id: Makefile.in,v 1.33 2002/09/27 22:16:24 wcc Exp $

SHELL = /bin/sh
top_srcdir = .
srcdir = .

prefix = /usr/local/program
DEST = ${prefix}
......

Weiterhin kann man zum Beispiel die Lage der Include Datein angeben, da das Configure-Script sich da schön öfter irrt. Dies geschieht durch die Option

./configure wie z.B. --libir=/path/to/include

Die Methode von Hand ist meistens der sichere Weg.


make - Kompilieren

Nach der Erzeugung des Makefile, steht der Kompilierung des Source-Codes nichts mehr im Weg. Der einfachste Aufruf zum Kompilieren, welcher in 99,5% aller Fälle benutzt wird, lautet:

$ make

Es gibt aber auch durchaus andere Befehle, um das Kompilieren zu starten, welche aber in der ReadMe- oder INSTALL-Datei stehen werden. Auch in der make Prozedur kann es zu Fehlern kommen, in den meisten Fällen liegt dies daran, das der Compiler notwendige Include Datein nicht finden kann (erkennbar an der Endung .h). Dieses Problem tritt meistens auf, wenn das Makefile per Hand erstellt wurde.

$ make
make[1]: Entering directory `/usr/local/program-src/src‘
(This may take a while.  Go get some runts.)
gcc -pipe -g -O2 -Wall -I.. -I.. -DHAVE_CONFIG_H   -c botcmd.c
gcc -pipe -g -O2 -Wall -I.. -I.. -DHAVE_CONFIG_H   -c botmsg.c
gcc -pipe -g -O2 -Wall -I.. -I.. -DHAVE_CONFIG_H   -c dns.c
make: error: Xlib.h not found

Hier zum Beispiel wurde die Datei Xlib.h nicht gefunden. Der angegebene Pfad ist immer relativ zu dem Verzeichnis, wo der Compiler die Include Dateien sucht. Nun muss man erst mal rausfinden, wo sich die Datei befindet:

$ find / -name xlib.h
/usr/X11R6/include/Xlib.h

Wir haben die Datei nun unter /usr/X11R6/include/Xlib.h gefunden. Wir müssen dem Compiler nun mitteilen, das er nicht nur in den standardmäßig vorgegeben Pfaden gesucht wird, sondern auch in den so eben gefundenem Verzeichnis. Dies kann entweder manuell im Makefile eingefügt werden:

CFLAGS = $ (DEFINES) -O2 -I/usr/X11R6/

Wenn man die Änderungen nicht manuell durchführen will, kann man dies auch folgendermaßen machen:

$ CFLAGS=-/usr/X11R6 ./configure

Eine dritte Möglichkeit ist folgender Weg, hierbei sollte man aber die Option –help nutzen um beim Configure-Script zu checken, ob die Option –libdir existiert oder eventuell anders heißt.

$ ./configure --libdir=/usr/X11R6

So nun kann man das Programm erneut kompilieren.

$ make
make[1]: Entering directory `/usr/local/program-src/src‘
(This may take a while.  Go get some runts.)
gcc -pipe -g -O2 -Wall -I.. -I.. -DHAVE_CONFIG_H   -c botcmd.c
gcc -pipe -g -O2 -Wall -I.. -I.. -DHAVE_CONFIG_H   -c botmsg.c
gcc -pipe -g -O2 -Wall -I.. -I.. -DHAVE_CONFIG_H   -c dns.c
........

All modules compiled.

make[1]: Leaving directory `/usr/local/program-src/src/mod‘

modules made:
-rwxr-xr-x    1 lamont   lamont       9012 Sep 16 12:27 assoc.so
-rwxr-xr-x    1 lamont   lamont      12860 Sep 16 12:27 dns.so
-rwxr-xr-x    1 lamont   lamont      13692 Sep 16 12:27 wire.so

Now run "make install" to install your program.

Somit ist das Programm fertig und fehlerfrei kompiliert und bereit zur Installation.


Installation

Das gewünschte Programm ist nun fertig kompiliert, und muss nun noch an die richtige stelle kopiert werden. Handelt es sich nur um eine Datei, könnte man es auch "von Hand" durchführen, aber da viele Programme nicht nur aus der Binary sondern aus vielen Dateien, wie z.B. Config‘s, Man-Pages oder anderen bestehen, würde es sehr schnell in Arbeit ausarten. Statt dessen lässt man make diese Aufgabe erfüllen, hierzu ist es nun nötig sich als Root auf dem System einzuloggen:

# make install

Program v1.6.034 (C) 2004 Robert Madlo (C) 2004 Planet-rcs.de

Installing in directory: ‘/usr/local/program/‘.
Copying done.
Installation completed.

Dieser Befehl wird nun das Programm in das Verzeichnis kopieren welchen man unter dem Punkt ./configure --prefix=/usr/local/program festgelegt hat. In unserem Beispiel wird die kompilierte Binary und alles Files und Unterordner in /usr/local/program installiert.

Will man zuerst sehen, was der make install Befehl bewirkt, und ob alle Pfade für die entgültige Installation richtig gesetzt sind, kann man mit der Option "-n" einen "Probedurchgang" fahren.

# make -n install

Einen Nachteil hat die Installation mit make jedoch - sie läßt sich nur schwer wieder rückgängig machen. Dies war auch ein Grund dafür, das die Paketentwicklung immer weiter vorangetrieben wird. Beispiele hierfür sind zum einem RPM, wie sie Redhat benutzt oder die Debian Pakete (deb, dpkg).

Mit einem kleinen Trick kann man aber die neu installierten Dateien sich ausgeben lassen.

# touch ts 
# make install
# find / -cnewer ts > logfile

In der Datei logfile stehen nach der Installation alle neuen Dateien.

Somit ist das Kompilieren und Installieren eines Programms abgeschlossen.


Das System aufräumen

Das program-src.tar.gz Archiv brauchen wir nicht mehr. Hingegen sollten wir das program-src Verzeichnis anders behandeln. Manche Programme unterstützen ein make deinstall, da benötigen wir auch dieses Verzeichnis weiterhin, da es wichtige Informationen für eine Deinstallation enthält. Allerdings enthält das Verzeichnis auch temporär angelegte Dateien, die für uns keinen Nutzen mehr haben. Diese können wir einfach entfernen:

$ cd /usr/local/program-src/
$ make clean

Wird die Funktion make deinstall nicht unterstützt, brauchen wir das program-src Verzeichnis nicht mehr und sie können es einfach rekursiv löschen. Man sollte aber mit dieser Funktion vorsichtig sein, das sie in vielen Fällen z.B. das Makefile löscht oder auf Default zurückt setzt, was in manchen Fällen nicht erwünscht ist.

$ rm -rf /usr/local/program-src/

Die sicherste Methode ist allerdings immer noch die Deinstallation von Hand. Wenn man bei der Installation ein Logfile angelegt hat, kann man dieses sehr gut auch zum deinstallieren nutzen, und kann so sicher sein, dass man alle Dateien und Ordner wieder entfernen kann.

Mit diesem Schritt ist das Kompilieren und Installieren nun beendet. Zwar konnte dieser Artikel nur einen groben Überblick über die Prozedur geben, aber es sollte für Anfänger reichen ihr erstes Programm zu kompilieren. Bei größeren Programmen kann es zu komplizierteren Optionen, welche man dem Configure Script mitteilen muss. Aber hierzu gibt es in vielen Fällen gut dokumentiere INSTALL oder ReadMe Datein.

 


 

Vielleicht auch interessant:


Über den Autor

Robert programmiert Webanwendungen in ASP, kennt sich bestens im IRC und mit Eggdrops aus und schreibt auch darüber Artikel auf planet-rcs.de

Feedback