| 
					Wenn man ein Programm in C, C++ oder einer anderen Kompilersprache schreibt, muss man den Quellcode mit dem Kompiler in ein ausführbares Programm übersetzen. Bei der GNU Compiler Collection (GCC) von RISC OS sind bei C dazu zwei Schritte in der Kommandozeile notwendig. Die sehen zum Beispiel wie folgt aus.
					 
   gcc -c HalloWelt1.c -o HalloWelt1.o
   gcc -o HalloWelt1 HalloWelt1.o
					 
					In der ersten Zeile wird aus dem Quellcode eine Objektdatei kompiliert, die dann in der zweiten Zeile zu einen ausführbaren Programm gelinkt wird. Diese beide Zeilen bei der Programmentwicklung immer und immer wieder zu tippen ist nichts für Programmierer. Also packt man die beiden Zeilen in ein Obey oder TaskObey und kann dieses dann in der Kommandozeile oder per Doppelklick aufrufen um das Programm zu erstellen.
					 
					Mit Make wurde den Programmierern ein Werkzeug in die Hand gegeben das besser für diese Aufgabe geeignet ist, als ein (Task)Obey, Shellskript und so weiter.
					 
					Beim Acorn C/C++, das später Castle C/C++ hieß und nun Desktop Development Environment heißt gibt es amu inklusive graphischer Oberfläche. Hier beziehe ich mich aber nur auf die GNU Compiler Collection und das GNU Make. Einiges kann man aber für amu übernehmen. Zusätzlich kann man GNU Make auch mit dem Desktop Development Environment nutzen. GNU Make ist nicht Bestandteil von GCC und muss extra herunterladen und installieren werden.
					 
					Damit Make seine Arbeit aufnehmen kann, muss man noch eine Konfiguration, das Makefile, erstellen. Zuerst noch ein kleiner C Quellcode damit Make und GCC etwas zu tun bekommt und man ein Ergebnis in den Händen halten kann. 
   /* HalloWelt 1 */
   #include <stdio.h>
   int main(void) {
      puts("Hallo Welt 1");
      return 0;
   }
					
					 Dieses C-Programm bitte als HalloWelt1in das Verzeichniscspeichern. 
					In der Unixwelt und anderswo haben C-Quellcode zum Beispiel den Namen prog.c. Da unter RISC OS das Trennzeichen für Verzeichnisse der Punkt ist, gibt es bekanntermaßen ein Problem. Unter RISC OS wird in der Regel dannprog/coder bei einen JPEG Bildbild/jpggeschrieben. Aber gerade bei C/C++ wurde festgelegt, dass die C-Quelltexte in das Verzeichniscgelegt werden und keine Endung/cerhalten. Auch wenn der Quelltextprogim Verzeichniscliegt, so heißt für GCC und Make der Quelltextprog.c. Dito mit der Objektdateio.progdie dann alsprog.oaufgerufen wird. Das ist auf den ersten Blick verwirrend, ist aber nun mal so festgelegt worden. Im folgende werde ich zum Beispielprog.cschreiben, auch wenn die Dateiprogim Verzeichniscgemeint ist. Ansonsten müsste ichprog.caliasc.progschreiben und das recht häufig. Das selbe mitprog.oaliaso.progund mitprog.haliash.prog. Auf die wenigen Ausnahmen werde ich dann hinweisen. 
					Nun muss die Datei Makefilemit folgenden Inhalt im gleichen Verzeichnis in dem das Verzeichniscliegt in einen Texteditor erstellt werden. 
   HalloWelt1: HalloWelt1.o
      gcc -o HalloWelt1 HalloWelt1.o
   HalloWelt1.o: HalloWelt1.c
      gcc -c -o HalloWelt1.o HalloWelt1.c
					
					Es handelt sich hier um zwei Regeln. In der ersten Zeile des Makefiles ist HalloWelt1die Zieldatei der ersten Regel. Die Zieldatei ist abhängig vonHalloWelt1.o. Das heißt nichts anderes, das man die ObjektdateiHalloWelt1.obraucht um das ausführbare ProgrammHalloWelt1zu erhalten. Das erreicht man durch das Linken der ObjektdateiHalloWelt1.o. Ziel und die notwendige Datei sind mit einen Doppelpunkt getrennt. Nun folgt in der zweiten Zeile das Kommando um das Ziel zu erreichen, also das Linken. Das ist die zweite Kommandozeile von oben. Diese Zeile ist eingerückt. Die Einrückung besteht nicht aus Leerschritten, sondern aus einen Tabzeichen. Das ist sehr wichtig, diese Zeile muss mit einen Tab eingerückt sein. Je nach Editor beziehungsweise Einstellung des Editors erzeugt ein Druck auf die Tabtaste kein Tab, sondern mehrere Leerzeichen. Ohne die Tab-Einrückung wird Make nicht seiner Aufgabe nachgehen können. 
					Mit der zweiten Regel verhält es sich sehr ähnlich. Hier ist das Ziel HalloWelt1.ound ist von der DateiHalloWelt1.cabhängig. In der nachfolgenden Zeile wird der Quellcode zur Objektdatei kompiliert. Ruft man nun in der Kommandozeilemakeauf, dann wird zuerst der Quellcode kompiliert und dann das ausführbare Programm erstellt. Ruft man ein zweites Malmakeauf oder hat vorher schon das Programm per Hand erstellt, dann wird Make nur melden, dass nichts zu tun ist. Löscht man jetzt die DateiHalloWelt1undo.HalloWelt1, dies ist die RISC OS Schreibweise, und ruft dann noch malmakeauf, wird erst kompiliert und dann gelinkt. Löscht man nurHalloWelt1wird nur gelinkt. Die ObjektdateiHalloWelt1.oist ja noch vorhanden und muss nicht neu erstellt werden. 
					Make schaut bei einen Aufruf nach, ob die Zieldatei vorhanden ist. Also im ersten Schritt wird geschaut ob HalloWelt1vorhanden ist. Ist die ZieldateiHalloWelt1vorhanden, dann wird geschaut ob die abhängige Datei, hierHalloWelt1.o, jünger als das Ziel ist. IstHalloWelt1.ojünger, dann ist die Zieldatei veraltet und muss neu erstellt werden. Aber zuerst wird noch geprüft ob es auch eine Regel fürHalloWelt1.ogibt und die gibt es in der zweiten Regel. Wie bei der ersten Regel wird geprüft obHalloWelt1.oexistiert oder nicht älter als die abhängige Datei, hierHalloWelt1.c, ist. FürHalloWelt1.cgibt es keine Regel und wennHalloWelt1.cjünger ist beziehungsweiseHalloWelt1.onicht vorhanden ist, dann wird nun zuerst die zweite Regel ausgeführt undHalloWelt1.okompiliert. Dann muss nach der ersten RegelHalloWelt1erstellt werden. 
					Bei den Make-Regeln dreht es sich also im wesentlichen darum ob das Ziel älter als die abhängige Datei ist. In diesen Beispiel ergibt sich kein Vorteil zu einen (Task)Obey, da HalloWelt1.cdie einzige Datei ist, die man bei der Entwicklung ändert. Und nach einer Änderung muss immer kompiliert und gelinkt werden um die Änderung im Programm zu erhalten. 
					Bei größeren Projekten gibt es mehrere Gründe warum man ein Programm im mehrere Quelldateien unterteilt. Jeder Quelltext muss dann einzeln kompiliert und am Schluss gelinkt werden.
					 
   gcc -c HalloWelt2.c -o HalloWelt2.o Nummer2.o
   gcc -c -o Nummer2.o Nummer2.c
   gcc -o HalloWelt2 HalloWelt2.o
					 
					Wenn das in ein (Task)Obey eingetragen wurde, dann werden immer beide Quellcode kompiliert, auch wenn man nur an einer der beiden Quelltexte etwas geändert hat. Der andere Quelltext braucht eigentlich nicht kompiliert zu werden, da sich dort nichts geändert hat. Da die Kompilation doch etwas dauert, kann man etwas Zeit sparen, wenn man ein Tool hat das prüft ob die Quelle jünger als die zugehörige Objektdatei ist. Das Tool kenne wir schon. Erstellen wir ein C-Programm, das aus zwei Quelltexten besteht.
					 
   /* HalloWelt 2 */
   #include <stdio.h>
   /* int nummer_zwei(); */
   #include "Nummer2.h"
   int main(void) {
      printf("Hallo Welt %i\n", nummer_zwei());
      return 0;
   }
					
					Der erste Quellcode HalloWelt2.cruft die Funktionnummer_zwei()auf. Diese Funktion ist inNummer2.cvorhanden. 
   /* Nummer 2 */
   int nummer_zwei() {
      return 2;
   }
					
					Nun muss man eine neues Makefileanlegen. Benennen wir das alte zuerst inMakefile1um. Falls man das später noch benutzen möchte, kann man es mitmake -f Makefile1aufrufen. 
   HalloWelt2: HalloWelt2.o Nummer2.o
      gcc -o HalloWelt2 HalloWelt2.o Nummer2.o
   HalloWelt2.o: HalloWelt2.c
      gcc -c -o HalloWelt2.o HalloWelt2.c
   Nummer2.o: Nummer2.c
      gcc -c -o Nummer2.o Nummer2.c
					
					Das erste Ziel HalloWelt2hat nun zwei Dateien von dem es abhängt. Diese sindHalloWelt2.oundNummer2.o. Für beide Objektdateien gibt es jeweils eine Regel, die der RegelHalloWelt1.oaus dem ersten Beispiel gleichen. Der wesentliche Unterschied zum erstenMakefileist, das es mehrere Abhängigkeiten für ein Ziel geben kann. Ist einer der beiden Dateien, alsoHalloWelt2.ooderNummer2.o, jünger alsHalloWelt2, dann muss neu gelinkt werden. Vorher prüft Make natürlich wieder ob die Objektdateien noch auf dem aktuellen Stand sind. 
					Im Gegensatz zu einen (Task)Obey wird nur kompiliert, wenn es notwendig ist. Das kann je nach Projekt einige Minuten bei einer Änderung im Quellcode sparen. Hier ist Make klar vorzuziehen.
					 
					Normalerweise wird die Zeile die auf die externe Funktionen hinweist in eine eigene Headerdatei geschrieben. Löschen wir also die Zeile int nummer_zwei();ausHalloWelt2.cund tragen dafür#include "Nummer2.h"ein. Dann muss im Verzeichnishdie DateiNummer2anlegen und dortint nummer_zwei();einfügen werden. Einmakewird zwar jetzt noch funktionieren, aber Make wird Änderung inNummer2.hnicht berücksichtigen. Also fügen wir in der zweiten Make-Regel mit dem ZielHalloWelt2.onochNummer2.hals abhängige Datei am Ende hinzu. 
   ...
   HalloWelt2.o: HalloWelt2.c Nummer2.h
      gcc -c -o HalloWelt2.o HalloWelt2.c
   ...
					
					Ändert man nun etwas an Nummer2.hoder ruft*Stamp h.Nummer2, dann wird die RegelHalloWelt2.oausgeführt und danach natürlich gelinkt. Da*Stampein eingebautes RISC OS Kommando ist, wird es in der RISC OS Schreibweise genutzt. 
					In vielen Makefiles gibt es das Ziel allundclean. Aber nirgends ist eine Dateiallodercleanzu finden, die mit den Regeln erstellt wurde. Erst Mal zuclean. Wenn man in dem zweitenMakefilenun am Ende die Regel 
   clean:
      Wipe o.HalloWelt2 ~CFV
      Wipe o.Nummer2 ~CFV
      Wipe HalloWelt2 ~CFV
					
					 hinzufügt und man makeaufruft, wird nichts neues passieren. Wenn man abermake cleanaufruft wird die Regelcleanaufgerufen. Nebenbeicleanhängt von keiner Datei oder einer anderen Regel ab und wird damit immer ausgeführt, wenn die Regel aufgerufen wurde. Die Kenner der RISC OS Kommandozeile wissen was das Kommando*Wipemacht. Es löscht Dateien. Hier die DateienHalloWelt2.o,Nummer2.oundHalloWelt2. In einer Regel kann man also auch mehrere Kommandos ausführen lassen. Natürlich sind alle diese Zeilen mit Tab eingerückt. Hat manmake cleanausgeführt, dann kann man mitmakedas Projekt wieder bauen. mitmake cleanerhält man ein sauberes Projekt ohne Objektdateien und dem ausführbaren Programm. Statt die beiden Objektdateien einzeln zu löschen, hätte man auchWipe o.* ~CFVeintragen können. Dann würde aber auchHalloWelt1.ogelöscht. In einen realen Projekt isto.*sicherlich die einfachere Lösung. 
					Nun zur Regel all. Wenn man die Regelcleanaufgerufen hat, sollte man nunmake Nummer2.oin die Kommandozeile eingeben. Dann wird nur die RegelNummer2.oangewendet. Einmakedanach wird die RegelHalloWelt2.oundHalloWelt2abarbeiten. Man kann also, wie mitmake clean, eine beliebige Regel gezielt aufrufen. Wenn man nurmakeaufruft wird die erste Regel, also hierHalloWelt2inklusive deren Abhängigkeiten ausgeführt. Ein Projekt kann mehrere Programme erstellen. Um sicherzustellen, das das gesamte Projekt erstellt wird, wird oft die Regelalleingeführt. Wenn man das ersteMakefilefürHalloWelt1in das aktuelleMakefileeinfügen, kann man mitmake HalloWelt1undmake HalloWelt2die beiden Programme getrennt erstellen. Aber mitmakewird man beide Programme mit einen Aufruf erstellen. 
   all: HalloWelt1 HalloWelt2
   HalloWelt1: HalloWelt1.o
      gcc -o HalloWelt1 HalloWelt1.o
   HalloWelt1.o: HalloWelt1.c
      gcc -c -o HalloWelt1.o HalloWelt1.c
   HalloWelt2: HalloWelt2.o Nummer2.o
      gcc -o HalloWelt2 HalloWelt2.o Nummer2.o
   HalloWelt2.o: HalloWelt2.c Nummer2.h
      gcc -c -o HalloWelt2.o HalloWelt2.c
   Nummer2.o: Nummer2.c
      gcc -c -o Nummer2.o Nummer2.c
   clean:
      Wipe o.* ~CFV
      Wipe HalloWelt1 ~CFV
      Wipe HalloWelt2 ~CFV
					
					Den einen oder anderen ist vielleicht etwas aufgefallen bei Zeilen wie folgende.
					 
   HalloWelt1: HalloWelt1.o
      gcc -o HalloWelt1 HalloWelt1.o
					
					HalloWelt1undHalloWelt1.okommen in der Regel zweimal vor. Make erlaubt einen hier etwas Tipparbeit zu sparen. Die Zieldatei kann man auch mit$@beschreiben. Die erste Abhängigkeit kann man mit$<darstellen. Die beiden Zeilen kann man damit als 
   HalloWelt1: HalloWelt1.o
      gcc -o $@ $<
					
					schreiben. Hat man mehrere Abhängigkeiten, so kann man $?benutzen, also zum Beispiel: 
   HalloWelt2: HalloWelt2.o Nummer2.o
      gcc -o $@ $?
					
					Das macht die ganze Sache etwas übersichtlicher und kürzer. Man kann auch selber Variablen festlegen. So kann man zum Beispiel mit CFLAGS = -O3die VariableCFLAGSeinrichten. Dies sollten man am Anfang des Makefiles machen und es es ist Standard Variablen durchgehend groß zu schreiben. Man kann aber Variablen auch kleinschreiben. Wichtig ist nur, das Make die Groß- und Kleinschreibung beachtet. Weiter unten kann man dann mitgcc $(CFLAGS) -c -o $@ $<den Aufruf gestalten. DasMakefilesieht nun wie folgt aus. 
   CC = gcc
   LD = gcc
   CFLAGS = -O3
   all: HalloWelt1 HalloWelt2
   HalloWelt1: HalloWelt1.o
      $(LD) -o $@ $<
   HalloWelt1.o: HalloWelt1.c
      $(CC) $(CFLAGS) -c -o $@ $<
   HalloWelt2: HalloWelt2.o Nummer2.o
      $(LD) -o $@ $?
   HalloWelt2.o: HalloWelt2.c Nummer2.h
      $(CC) $(CFLAGS) -c -o $@ $<
   Nummer2.o: Nummer2.c
      $(CC) $(CFLAGS) -c -o $@ $<
   clean:
      Wipe o.* ~CFV
      Wipe HalloWelt1 ~CFV
      Wipe HalloWelt2 ~CFV
					
					Der Einsatz von Variablen hat auch den Vorteil, dass man später recht schnell und einfach und an einer Stelle den Inhalt einer Variablen austauschen kann. Auch Libraries kann man so dem Kompiler mitgeben.
					 
					Mit dem GNU Make kann man noch mehr anstellen. Ich denke das wichtigste habe ich hier erwähnt. Wer neugierig geworden ist, sollte sich die sehr ausführliche Dokumentation durchlesen. Im Netz gibt es die eine oder andere Seite mit Interessanten zum Thema Make. Dann aber meist für Linux und weniger für RISC OS.
					 
					Die Quellcode und die Makefiles kann man sich hier herunterladen. Viele Spaß beim Programmieren.
					 |