FreeBSD Developers' Handbook
Zurück | Kapitel 2. Werkzeuge zur Programmierung | Weiter

# 2.4. Kompilieren mit dem `cc`

Dieser Abschnitt behandelt ausschließlich den GNU Compiler für C und C++, da dieser bereits im Basissystem von FreeBSD enthalten ist. Er kann mittels `cc` oder `gcc` aufgerufen werden. Die Details zur Erstellung einer Anwendung mit einem Interpreter variieren zwischen verschiedenen Interpretern mehr oder weniger stark, und werden meist ausführlich in der zugehörigen Dokumentation oder Online-Hilfe beschrieben.

Sobald Sie Ihr Meisterwerk fertig geschrieben haben besteht der nächste Schritt darin, dieses (hoffentlich!) unter FreeBSD zum Laufen zu bekommen. Dies beinhaltet üblicherweise mehrere Schritte, wobei jeder einzelne Schritt von einem separaten Programm durchgeführt wird.

1. Aufbereiten Ihres Quelltextes durch Entfernen von Kommentaren, sowie weiteren Tricks wie das Ersetzen von Macros in C.

2. Überprüfen der Syntax Ihres Quelltextes, um die Einhaltung der Sprachregeln sicherzustellen. Wenn Sie diese verletzt haben werden entsprechende Fehlermeldungen Ihnen dies mitteilen!

3. Übersetzen des Quelltextes in Assemblersprache --diese ist dem eigentlichen Maschinencode schon sehr nahe, jedoch immer noch für Menschen lesbar. Angeblich. [1]

4. Übersetzen der Assemblersprache in Maschinencode--genau, wir sprechen hier von Bits und Bytes, Einsen und Nullen.

5. Überprüfen, ob Sie Dinge wie Funktionen und globale Variablen in einheitlicher Weise verwendet haben. Wenn Sie z.B. eine nicht existierende Funktion aufgerufen haben, wird eine entsprechende Fehlermeldung Ihnen dies mitteilen.

6. Wenn aus mehreren Quelltextdateien eine ausführbare Datei erstellt werden soll wird herausgefunden, wie die einzelnen Codeteile zusammengefügt werden müssen.

7. Ausarbeiten, wie das Programm aussehen muss, damit der Lader zur Laufzeit des Systems dieses in den Speicher laden und ausführen kann.

8. Endgültiges Schreiben der ausführbaren Datei in das Dateisystem.

Das Wort kompilieren wird häufig für die Schritte 1 bis 4 verwendet--die anderen werden mit dem Wort verlinken zusammengefasst. Manchmal wird Schritt 1 auch als Pre-Processing und die Schritte 3-4 als assemblieren bezeichnet.

Glücklicherweise werden alle diese Details vor Ihnen verborgen, da `cc` ein Frontend ist, welches sich um die Ausführung all dieser Programme mit den richtigen Argumenten für Sie kümmert; einfaches eingeben von

    % cc foobar.c

führt zur Übersetzung von `foobar.c` durch alle bereits erwähnten Schritte. Wenn Sie mehr als eine Datei übersetzen wollen müssen Sie etwas wie folgt eingeben

    % cc foo.c bar.c

Beachten Sie, daß die Überprüfung der Syntax genau dies tut--das reine Überprüfen der Syntax. Es findet keine Überprüfung bzgl. logischer Fehler statt, die Sie vielleicht gemacht haben, wie z.B. das Programm in eine Endlosschleife zu versetzen, oder Bubble Sort zu verwenden, wenn Sie eigentlich Binary Sort benutzen wollten. [2]

Es gibt haufenweise Optionen für `cc`, die alle in der zugehörigen Manualpage beschrieben werden. Im Folgenden werden ein paar der wichtigesten Optionen mit Beispielen ihrer Anwendung gezeigt.

`-o `filename``

  Die Name der Ausgabedatei. Wenn Sie diese Option nicht verwenden erstellt `cc` eine Datei mit dem Namen `a.out`. [3]

      % cc foobar.c               executable is a.out
      % cc -o foobar foobar.c     executable is foobar

`-c`

  Dies kompiliert die Datei nur, verlinkt sie jedoch nicht. Nützlich für Spielereien, um die Syntax auf Korrektheit zu überprüfen, oder falls Sie ein `Makefile` verwenden.

      % cc -c foobar.c

  Dieser Befehl erzeugt eine Objektdatei (nicht ausführbar) mit den Namen `foobar.o`. Diese kann mit anderen Objektdateien zusammen zu einer ausführbaren Datei verlinkt werden.

`-g`

  Diese Option erzeugt die Debug-Version einer ausführbaren Datei. Dabei fügt der Compiler zusätzliche Informationen darüber, welcher Funktionsaufruf zu welcher Zeile im Quelltext gehört, der ausfürbaren Datei hinzu. Ein Debugger kann Ihnen mit Hilfe dieser Information den zugehörigen Quelltext anzeigen, während Sie den Programmverlauf schrittweise verfolgen, was sehr hilfreich sein kann; der Nachteil dabei ist, daß durch die zusätzlichen Informationen das Programm viel größer wird. Normalerweise verwendet man die Option `-g` während der Entwicklung eines Programms, und für die “Release-Version”, wenn man von der Korrektheit des Programms überzeugt ist, kompiliert man das Programm dann ohne diese Option.

      % cc -g foobar.c

  Mit diesem Befehl wird eine Debug-Version des Programms erzeugt. [4]

`-O`

  Diese Option erzeugt eine optimierte Version der ausführbaren Datei. Der Compiler verwendet einige clevere Tricks, um das erzeugte Programm schneller zu machen. Sie können hinter der Option `-O` eine Zahl angeben, um eine höheres Level der Optimierung festzulegen. Dadurch wird jedoch häufig eine fehlerhafte Optimierung seitens des Compilers aufgedeckt. Zum Beispiel erzeugte die Version des `cc`, welche mit dem FreeBSD Release 2.1.0 mitgeliefert wurde, bei Verwendung der Option `-O2` unter bestimmten Umständen falschen Code.

  Optimierungen werden normalerweise nur beim Kompilieren von Release-Versionen aktiviert.

      % cc -O -o foobar foobar.c

  Durch diesen Befehl wird eine optimierte Version von `foobar` erzeugt.

Die folgenden drei Flags zwingen den `cc` dazu, Ihren Code auf die Einhaltung der internationalen Standards hin zu überprüfen, welche häufig als ANSI Standards bezeichnet werden, obwohl sie streng genommen zum ISO Standard gehören.

`-Wall`

  Aktivieren aller Warnmeldungen, die die Autoren des `cc` für wichtig halten. Trotz des Namens dieser Option werden dadurch nicht sämtliche Warnungen ausgegeben, die der `cc` ausgeben könnte.

`-ansi`

  Deaktivieren der meisten, jedoch nicht aller, nicht-ANSI C Eigenschaften, die der `cc` bietet. Trotz des Namens ist durch diese Option nicht sichergestellt, daß Ihr Code diese Standards auch vollständig einhält.

`-pedantic`

  Deaktivieren aller Eigenschaften des `cc`, welche nicht konform zu ANSI C sind.

Ohne diese Flags wird Ihnen der `cc` die Verwendung eigener Erweiterungen des Standards erlauben. Einige dieser Erweiterungen sind zwar sehr nützlich, werden jedoch nicht von anderen Compilern unterstützt--eigentlich ist eines der Hauptziele des Standards, das Leute Code so schreiben können, daß dieser mit jedem Compiler auf beliebigen Systemen funktioniert. Dies wird häufig als portabeler Code bezeichnet.

Im Allgemeinen sollten Sie versuchen, Ihren Code so portabel wie möglich zu schreiben, da Sie ansonsten eventuell das gesamte Programm noch einmal neu schreiben müssen, falls dieser in einer anderen Umgebung laufen soll--und wer weiß schon was er in ein paar Jahren verwenden wird?

    % cc -Wall -ansi -pedantic -o foobar foobar.c

Durch diesen Befehl wird eine ausführbare Datei namens `foobar` erzeugt, nachdem `foobar.c` auf die Einhaltung der Standards überprüft wurde.

`-l`library``

  Mit dieser Option kann eine Bibliothek mit Funktionen angegeben werden, die während des Verlinkens verwendet wird.

  Das am häufigsten auftretende Beispiel dieser Option ist die Übersetzung eines Programmes, welches einige der mathematischen Funktionen in C verwendet. Im Gegensatz zu den meisten anderen Plattformen befinden sich diese Funktionen in einer separaten Bibliothek, deren Verwendung Sie dem Compiler explizit mitteilen müssen.

  Angenommen eine Bibliothek heißt `lib`irgendwas`.a`, dann müssen Sie dem `cc` als Argument `-l`irgendwas`` übergeben. Zum Beispiel heißt die Mathematik-Bibliothek `libm.a`, und daher müssen Sie dem `cc` als Argument `-lm` übergeben. Ein typisches “Manko” der Mathematik-Bibliothek ist, daß diese immer die letzte Bibliothek auf der Kommandozeile sein muß.

      % cc -o foobar foobar.c -lm

  Durch diesen Befehl werden die Funktionen aus der Mathematik-Bibliothek in `foobar` gelinkt.

  Wenn Sie C++-Code kompilieren wollen, müssen Sie `-lg++`, bzw. `-lstdc++` falls Sie FreeBSD 2.2 oder neuer verwenden, zu Ihrer Kommandozeile hinzufügen, um Ihr Programm gegen die Funktionen der C++ Bibliothek zu linken. Alternativ können Sie anstatt `cc` auch `c++` aufrufen, welcher dies für Sie erledigt. `c++` kann unter FreeBSD auch als `g++` aufgerufen werden.

      % cc -o foobar foobar.cc -lg++     Bei FreeBSD 2.1.6 oder älter
      % cc -o foobar foobar.cc -lstdc++  Bei FreeBSD 2.2 und neuer
      % c++ -o foobar foobar.cc

  Beide Varianten erzeugen eine ausführbare `foobar` aus der C++ Quelltextdatei `foobar.cc`. Beachten Sie bitte, daß auf UNIX® Systemen C++ Quelltextdateien üblicherweise auf `.C`, `.cxx` oder `.cc` enden, und nicht wie bei MS-DOS® auf `.cpp` (welche schon anderweitig benutzt wurde). Der `gcc` hat normalerweise anhand dieser Information entschieden, welcher Compiler für die Quelltextdatei zum Einsatz kommen soll; allerdings gilt diese Einschränkung jetzt nicht mehr, und Sie können Ihre C++-Dateien ungestraft auf `.cpp` enden lassen!

## 2.4.1. Häufig auftretende `cc`-Fragen und -Probleme

2.4.1.1. Ich versuche ein Programm zu schreiben, welches die Funktion `sin()` verwendet, erhalte jedoch eine Fehlermeldung. Was bedeutet diese?
2.4.1.2. So, ich habe jetzt dieses einfache Programm als Übung für `-lm` geschrieben. Alles was es macht ist, 2.1 hoch 6 zu berechnen.
2.4.1.3. Wie kann ich das korrigieren?
2.4.1.4. Ich habe eine Datei mit dem Namen `foobar.c` compiliert, kann jedoch nirgends eine ausführbare Datei namens `foobar` finden. Wo befindet sich diese?
2.4.1.5. OK, ich habe eine ausführbare Datei namens `foobar`, ich kann sie sehen, wenn ich `ls` aufrufe. Gebe ich jedoch `foobar` in die Kommandozeile ein wird mir gesagt, daß eine Datei mit diesem Namen nicht existiert. Warum kann die Datei nicht gefunden werden?
2.4.1.6. Ich habe meine ausführbare Datei `test` genannt, allerdings passiert nichts wenn ich diese aufrufe. Was ist hier los?
2.4.1.7. Ich habe mein Programm kompiliert und bei dessen Aufruf sah zuerst alles gut aus. Jedoch gab es dann eine Fehlermeldung, welche irgendetwas mit “`core dumped`” lautete. Was bedeutet das?
2.4.1.8. Faszinierendes Zeugs, aber was soll ich jetzt machen?
2.4.1.9. Als mein Programm den core dump erzeugt hat, sagte es etwas von einem “`segmentation fault`”. Was ist das?
2.4.1.10. Wenn ich einen core dump erhalte erscheint manchmal die Meldung “`bus error`”. In meinem UNIX-Buch steht, daß die Ursache ein Hardwareproblem sei. Der Computer scheint aber weiterhin zu funktionieren. Ist dies wahr?
2.4.1.11. Diese Sache mit den core dumps hört sich sehr nützlich an, wenn ich so etwas selber an beliebiger Stelle bewirken könnte. Kann ich das tun, oder muß ich warten bis ein Fehler auftritt?

2.4.1.1. Ich versuche ein Programm zu schreiben, welches die Funktion `sin()` verwendet, erhalte jedoch eine Fehlermeldung. Was bedeutet diese?

    /var/tmp/cc0143941.o: Undefined symbol `_sin' referenced from text segment

Wenn Sie mathematische Funktionen wie `sin()` verwenden wollen, müssen Sie den `cc` anweisen, die Mathematik-Bibliothek wie folgt zu verlinken:

    % cc -o foobar foobar.c -lm

2.4.1.2. So, ich habe jetzt dieses einfache Programm als Übung für `-lm` geschrieben. Alles was es macht ist, 2.1 hoch 6 zu berechnen.

    #include <stdio.h>

    int main() {
        float f;

        f = pow(2.1, 6);
        printf("2.1 ^ 6 = %f\n", f);
        return 0;
    }

und ich habe es wie folgt kompiliert:

    % cc temp.c -lm

wie mir gesagt wurde. Allerdings bekomme ich jetzt bei der Ausführung die folgende Ausgabe:

    % ./a.out
    2.1 ^ 6 = 1023.000000

Das ist nicht die richtige Antwort! Was ist hier los?

Wenn der Compiler Ihren Funktionsaufruf sieht, überprüft er, ob er schon einmal einen Prototypen für diese gesehen hat. Wenn nicht nimmt er als Rückgabewert den Typ int an, was sicherlich nicht das ist, was Sie an dieser Stelle wollen.

2.4.1.3. Wie kann ich das korrigieren?

Die Prototypen der mathematischen Funktionen befinden sich in der Datei `math.h`. Wenn Sie diese Datei in Ihrem Quelltext includen ist der Compiler in der Lage, den Prototypen zu finden, und wird aufhören, seltsame Dinge mit Ihrer Berechnung zu machen!

    #include <math.h>
    #include <stdio.h>

    int main() {
    ...

Nach erneutem Compilieren sollte das Folgende bei der Ausführung ausgegeben werden:

    % ./a.out
    2.1 ^ 6 = 85.766121

Wenn Sie irgendwelche mathematischen Funktionen verwenden sollten Sie immer die Datei `math.h` includen und nicht vergessen, Ihr Programm gegen die Mathematik-Bibliothek zu verlinken.

2.4.1.4. Ich habe eine Datei mit dem Namen `foobar.c` compiliert, kann jedoch nirgends eine ausführbare Datei namens `foobar` finden. Wo befindet sich diese?

Denken Sie daran, daß der `cc` die ausführbare Datei `a.out` nennt, wenn Sie nicht explizit einen Namen angeben. Verwenden Sie in solch einem Fall die Option `-o `filename``:

    % cc -o foobar foobar.c

2.4.1.5. OK, ich habe eine ausführbare Datei namens `foobar`, ich kann sie sehen, wenn ich `ls` aufrufe. Gebe ich jedoch `foobar` in die Kommandozeile ein wird mir gesagt, daß eine Datei mit diesem Namen nicht existiert. Warum kann die Datei nicht gefunden werden?

Im Gegensatz zu MS-DOS sucht UNIX nicht im aktuellen Verzeichnis nach einem ausführbaren Programm, das Sie versuchen auszuführen, solange Sie dies nicht explizit mit angeben. Sie können entweder `./foobar` eingeben, was soviel bedeutet wie “führe eine Datei namens `foobar` im aktuellen Verzeichnis aus”, oder Sie können Ihre Umgebungsvariable `PATH` so erweitern, daß sie ähnlich wie folgt aussieht

    bin:/usr/bin:/usr/local/bin:.

Der Punkt am Ende bedeutet “siehe im aktuellen Verzeichnis nach, wenn es in keinem der anderen zu finden war”.

2.4.1.6. Ich habe meine ausführbare Datei `test` genannt, allerdings passiert nichts wenn ich diese aufrufe. Was ist hier los?

Bei den meisten UNIX-Systeme existiert bereits ein Programm mit dem Namen `test` im Verzeichnis `/usr/bin`, und die Shell nimmt dieses, bevor sie im aktuellen Verzeichnis nachsieht. Sie können entweder den folgenden Befehl eingeben:

    % ./test

oder Sie können einen geeigneteren Namen für Ihr Programm wählen!

2.4.1.7. Ich habe mein Programm kompiliert und bei dessen Aufruf sah zuerst alles gut aus. Jedoch gab es dann eine Fehlermeldung, welche irgendetwas mit “`core dumped`” lautete. Was bedeutet das?

Der Name core dump stammt noch aus sehr frühen Zeiten von UNIX, als die Maschinen noch Kernspeicher zum Speichern von Daten verwendeten. Einfach ausgedrückt, wenn bei einem Programm unter bestimmen Bedingungen ein Fehler auftrat, hat das System den Inhalt des Kernspeichers auf der Festplatte in eine Datei namens `core` geschrieben, welche der Programmierer dann näher untersuchen konnte, um die Ursache des Fehlers herauszufinden.

2.4.1.8. Faszinierendes Zeugs, aber was soll ich jetzt machen?

Verwenden Sie den `gdb`, um das Speicherabbild zu untersuchen (siehe Abschnitt 2.6).

2.4.1.9. Als mein Programm den core dump erzeugt hat, sagte es etwas von einem “`segmentation fault`”. Was ist das?

Diese Meldung heißt im Prinzip, daß Ihr Programm eine illegale Operation mit dem Speicher durchführen wollte; UNIX wurde so entworfen, daß es das andere Programme und das Betriebssystem selbst vor wildgewordenen Programmen schützt.

Häufige Ursachen hierfür sind:

- Der Versuch, einen `NULL`-Zeiger zu beschreiben, z.B.

      char *foo = NULL;
      strcpy(foo, "bang!");

- Einen Zeiger zu verwenden, welcher noch nicht initialisiert wurde, z.B.

      char *foo;
      strcpy(foo, "bang!");

  Der Zeiger hat einen zufälligen Wert, welcher mit etwas Glück in einen Bereich des Speichers zeigt, der für Ihr Programm nicht verfügbar ist, und der Kernel bricht Ihr Programm ab, bevor es irgendwelchen Schaden anrichten kann. Wenn Sie Pech haben zeigt der Zeiger irgendwo mitten in Ihr eigenes Programm, und verändert dort ihre eigenen Datenstrukturen, was zu sehr seltsamen Fehlern Ihres Programmes führt.

- Der Versuch, auf Daten außerhalb eines Arrays zuzugreifen, z.B.

      int bar[20];
      bar[27] = 6;

- Der Versuch, Daten in eine Speicherbereich zu schreiben, der nur lesbar ist, z.B.

      char *foo = "My string";
      strcpy(foo, "bang!");

  UNIX-Compiler speichern häufig feste Zeichenketten wie `"My string"` in nur lesbaren Speicherbereichen ab.

- Wenn man unerlaubte Operationen mit `malloc()` und `free()` ausführt, z.B.

      char bar[80];
      free(bar);

  oder

      char *foo = malloc(27);
      free(foo);
      free(foo);

Einzelne solcher Fehler führen zwar nicht immer zu einem Fehlverhalten des Programms, stellen jedoch immer eine falsche Verwendung dar. Manche Systeme und Compiler sind toleranter als andere, weshalb Programme auf dem einen System einwandfrei laufen, auf dem anderen System jedoch abstürzen.

2.4.1.10. Wenn ich einen core dump erhalte erscheint manchmal die Meldung “`bus error`”. In meinem UNIX-Buch steht, daß die Ursache ein Hardwareproblem sei. Der Computer scheint aber weiterhin zu funktionieren. Ist dies wahr?

Nein, glücklicherweise nicht (es sei denn Sie haben wirklich ein Hardwareproblem...). Üblicherweise ist dies ein Weg Ihnen mitzuteilen, daß Sie auf Speicher in einer Weise zugegriffen haben, in der Sie dies nicht tun sollten.

2.4.1.11. Diese Sache mit den core dumps hört sich sehr nützlich an, wenn ich so etwas selber an beliebiger Stelle bewirken könnte. Kann ich das tun, oder muß ich warten bis ein Fehler auftritt?

Ja, nehmen sie einfach eine andere Konsole oder XTerm und führen Sie

    % ps

aus, um die Prozess-ID Ihres Programms herauszufinden. Führen Sie anschließend

    % kill -ABRT pid

aus, wobei ``pid`` die Prozess-ID ist, die Sie vorher ermittelt haben.

Dies ist nützlich, wenn sich Ihr Programm z.B. in einer Endlosschleife verfangen hat. Sollte Ihr Programm das Signal `SIGABRT` abfangen, gibt es noch andere Möglichkeiten, die denselben Effekt haben.

Alternativ können Sie einen core dump aus Ihrem Programm heraus erstellen, indem Sie die Funktion `abort()` aufrufen. Weitere Informationen darüber können Sie in der Manualpage abort(3) nachlesen.

Wenn Sie einen core dump von ausßerhalb Ihres Programms erzeugen wollen, ohne dabei den Prozess abzubrechen, können Sie das Programm `gcore` verwenden. Weitere Informationen dazu finden Sie in der zugehörigen Manualpage gcore(1).

### Fußnoten

[1] | Um genau zu sein übersetzt der `cc` den Quelltext an dieser Stelle nicht in Assemblersprache, sondern in seine eigene, maschinenunabhängige Sprache namens p-code.
[2] | Falls Sie es nicht wußten, Binary Sort ist, im Gegensatz zu Bubble Sort, eine effektive Möglichkeit, Dinge zu sortieren.
[3] | Der Grund dafür ist im Haufen der Geschichte begraben.
[4] | Beachten Sie, daß an dieser Stelle die Option `-o` zum Festlegen des Namens der ausführbaren Datei nicht verwendet wurde, weswegen an dieser Stelle die erzeugte Datei `a.out` heißt. Die Erzeugung einer Debug-Verion namens `foobar` ist als Übung dem Leser überlassen!

Zurück | Zum Anfang | Weiter
Einführung in die Programmierung | Nach oben | Make

Wenn Sie Fragen zu FreeBSD haben, schicken Sie eine E-Mail an <de-bsd-questions@de.FreeBSD.org>.
Wenn Sie Fragen zu dieser Dokumentation haben, schicken Sie eine E-Mail an <de-bsd-translators@de.FreeBSD.org>.