Tag 6: C, Compiler, Makefile, Buildprozess
TL;DR:
Im Open Source Bereich ist die meiste Software in C oder C++ geschrieben. Dies hat mehrere Gründe: Zum einen bestehen viele der Programme schon mehrere Jahrzehnte und zum anderen macht es diese besonders kompatibel. Aus diesem Grunde werden wir das Spiel auch in reinem C(99) schreiben. Somit sind wir schnell, plattformunabhängig, haben eine stabile Basis und ein Monster von Compiler zur Verfügung.
Zuerst einmal sollten wir klären, was C eigentlich genau ist. Die Programmiersprache hat mehrere Ausprägungen, da sie mit den Jahren an ihren Anforderungen gewachsen ist und dennoch streng standardisiert ist. Wir werden uns hier auf die Variante C99 von 1995 (ISO/IEC 9899:1999) stützen, weil der gcc so gut wie jede Plattform unterstützt und uns zum anderen im Vergleich zu den anderen Ausprägungen etwas mehr Komfort bietet.
Um C zu lernen empfiehlt es sich nicht, den 500 Seiten Standard zu lesen. Im Internet gibt es jede Menge besser lesbares Material dazu. Für Schnelleinsteiger würde ich das C Programming Tutorial von Alfred Park empfehlen, wer lieber ein Buch ließt sei C Programmieren von Anfang an von Helmut Erlenkötter empfohlen. Ich bin recht gut damit zurechtgekommen, vermutlich gibt es aber mittlerweile viel bessere Bücher dazu.
Eine Liste aller verfügbaren Funktionen ist auch ganz hilfreich. Wer unter Linux arbeitet, hat die komplette Dokumentation schon installiert und kann über den Befehl man
aufgerufen werden.
Ein minimales C Programm sieht so aus:
#include <stdio.h>
int main(int argc, char **argv) {
printf("Bald kommt der Nikolaus\\n");
return 0;
}
So, nachdem wir uns mit der Programmiersprache C beschäftigt haben und uns mit allerlei Resourcen ausgerüstet haben, geht es nun daran, den Programmcode zu übersetzen. Hierfür werden wir das überall eingesetzte Urgestein gcc verwenden. Dieser Compiler kann mittlerweile alle C und C++ Dialekte. Ein Aufruf sieht etwa so aus:
gcc -std=c99 -Wall -o game main.c
Das -std=c99 legt die C-Variante fest, das -W steht dafür Warnungen auszugeben und das all hinterher für alle. -o gibt die Ausgabedatei an, der letzte Parameter ist die Datei selbst.
Läuft soweit alles, machen wir uns daran, diesen Vorgang zu automatisieren, denn wenn es mehrere Dateien werden, wird es unübersichtlicher und immer umständlicher. Wir wollen das komplette Programm zukünftig mit einem einzigen Befehl zusammenbauen. Hierfür gibt es das bewährte Programm Make. Ähnlich wie Ant gibt es hier eine Konfigurationsdatei (Makefile) in der alle Tasks und Aktionen stehen. Für unser Minimalbeispiel von oben würde folgende Konfiguration ausreichen:
CC=gcc
CFLAGS=-Wall -Os -std=c99
all: main.c
$(CC) $(CFLAGS) -o game main.c
run:
./game
clean: game.o
rm game.o
Mit dem Aufruf make all
können wir nun das Projekt compilieren und mit make run
starten. make clean
räumt auf. Der Compiler und die Optionen habe ich in einer Variable ausgelagert, da wir hier später evtl. an zentraler Stelle noch Änderungen vornehmen müssen. Zu beachten ist auch, dass die Einrückungen aus genau einem TAB bestehen müssen, nicht aus Leerzeichen.
So, es gab viel Neues dieses mal. Ich habe absichtlich nicht alles im Detail erklärt, da ich euch nicht langweilen wollte. Dennoch bin ich sehr froh über Fragen aller Art in den Kommentaren. Falls etwas nicht funktioniert so wie hier beschrieben, helfe ich gerne weiter. Der hier besprochene Programmcode ist auf GitHub und kann dort angeschaut werden. Habt ihr bereits einen Fork des Projektes gemacht, könnt ihr die Änderungen mit dem Befehl git pull upstream master
in euer Projekt mit übernehmen. Das Makefile lässt nun Raum für weitere Tasks. Beispielsweise wäre ein install
-Task toll, der das Binary nach /usr/local/bin/ kopiert oder ein backup
-Task, der den Programmcode in ein tar.bz2-Archiv packt und nach /var/backups/ kopiert. Ich freue mich auf pull requests :)
Übermorgen geht es dann weiter mit der IDE. Wir werden uns Vim anschauen und einige Basics zur Programmierung mit C kennen lernen.