original in nl Wilbert Berendsen
nl to en Philip de Groot
en to de Guido Socher
Wilbert Berendsen ist professioneller Musiker und enthusiastischer Linuxbenutzer. Fr�her hat er mal Assemblercode f�r den Z80 geschrieben. Jetzt benutzt er Linux f�r all seine Arbeit. Aus Spa� schreibt er Einf�hrungsartikel und unterh�lt eine kleine Webseite unter http://www.xs4all.nl/~wbsoft/. Viva open source!
Fast jeder, der Linux nutzt, hat das Programm make schon
einmal benutzt. make kommt beim Kompilieren des Kernels, bei
der Installation eines Softwarepaketes und an vielen anderen Stellen
zum Einsatz. 'Make' ist ein sehr wichtiges Werkzeug f�r die
Softwareentwicklung.
Make hat jedoch noch viel mehr M�glichkeiten!
In diesem Artikel werden wir sehen, da� make ein leistungsf�higes Werkzeug f�r t�gliche Aufgaben wie das Schreiben von Artikeln, B�chern oder Webseiten sein kann. Im Laufe dieser Einf�hrung werden wir auch viele andere 'Unix Tricks' kennenlernen. Am Ende dieses Artikels werde ich dann noch ein paar Tips zu Make geben. Bitte beachte: Wir reden �ber Linux, aber im Prinzip kann man make auf jedem Betriebssystem einsetzen.
Wir brauchen ein einfaches System, um das Layout vom Inhalt zu trennen. Eine sehr leistungsf�hige L�sung w�re: Den Inhalt jedes Mal, wenn eine Seite angefragt wird, aus einer Datenbank zu lesen. PHP oder Microsoft ASP funktionieren so. Wir wollen jedoch einfach ganz normale HTML Seiten speichern. Desweiteren �ndert sich der Inhalt nicht so oft, damit eine Datenbank wirklich Sinn macht.
Wir werden einige einfache Befehle benutzen, um die Webseite zu bauen.
Piet hat z.B den Kopfteil einer Seite in header.html und das Seitenende in der Datei footer.html. Diese k�nnten etwa so aussehen:
<html><!-- the header --> <head> <title>Piet and Jan productions</title> </head> <body bgcolor="white"> <table border="0" width="100%"><tr> <td bgcolor="#c040ff" valign="top"> This is our website<br> Some rubbish is written down here.<br> We are very interactive<br> so this is our telephone number:<br> <b>0123-456789</b> </td><td valign="top"> <!-- Put the contents here -->und hier footer.html:
<!-- the footer --> </td></tr></table> </body></html>Damit sind z.B die Unix Kommandos um aus Jans Seiten die endg�ltigen Seiten zu machen:
cat header.html /home/jan/Docs/website/index.html echo -n '<hr>Last modification: ' date '+%A %e %B' cat footer.htmlWie diese Kommandos funktionieren, kannst du in den man-Seiten nachlesen. Die Ausgabe dieser Kommandos wird dann in die Datei /home/piet/public_html/index.html umgeleitet:
{ cat header.html /home/jan/Docs/website/index.html echo -n '<hr>Last modification: ' date '+%A %e %B' cat footer.html } > /home/piet/public_html/index.htmlDiese Prozedur kann auch auf die andere Datei (offer.html) angewendet werden.
Jedoch macht es keinen Sinn, immer wieder diese Kommandos von Hand einzugeben. Wir schreiben uns ein kleines Skript. Das Skript sollte sowohl ausgef�hrt werden, wenn Jan eine �nderung macht als auch nach einer �nderung von Piet an header/footer. Nichts sollte jedoch gemacht werden, wenn keiner von beiden etwas ge�ndert hat. Wir werden Linux f�r eine intelligente L�sung (lies: automatisch) benutzen!
Jetzt kommt make ins Spiel.
Make entscheidet, ob eine Anzahl von Kommandos ausgef�hrt werden m�ssen, basierend auf den Modifizierungszeiten der erzeugten Dateien und der Quelldateien.In anderen Worten: Falls eines der Quelldateien, die ben�tigt werden, um eine erzeugte Datei zu erstellen, neuer ist als die erzeugte Datei, dann m�ssen die Kommandos ausgef�hrt werden, und das Ziel dieser Kommandos ist es, eine neue Datei zu erzeugen.
Die erzeugte Datei nenne wir von nun an 'target' und die Quelldateien sind die `prerequisites'. Falls eines der `prerequisites' neuer als ein 'target' ist, dann , und nur dann, wird ein Kommando ausgef�hrt, um aus dem `prerequisites' ein neues 'target' zu machen.
Im augenblicklichen Arbeitsverzeichnis erzeugt man eine Datei mit dem Namen Makefile. Diese Datei enth�lt die Information, die von make ben�tigt wird.
make wird durch folgendes Kommando aufgerufen:
make target1 target2 ....
target ist optional. Falls das target fehlt, wird das erste im Makefile definierte target benutzt. Make sucht immer im augenblicklichen Arbeitsverzeichnis nach der Datei Makefile. Man kann mehr als nur ein target angeben.
# This is an example of a Makefile. # Comments can be put after a hash (#). target: prerequisites command target: prerequisites commando # and so on and so on.Wir fangen mit einem target an, gefolgt von einem Doppelpunkt und dann den ben�tigten prerequisites. Man kann eine Zeile verl�ngern, indem man sie mit einem backslash (\) beendet und dann in der n�chsten Zeile fortsetzt.
Die folgenden Zeilen enthalten dann ein oder mehrere Kommandos. Jede Zeile ist ein einzelnes Kommando. Falls ein Kommando zu lang ist und �ber mehrere Zeilen gehen soll, benutzt man zwei backslashes (\\) am Ende der Zeile.
Wichtige Anmerkung: Die Kommandozeilen werden durch einen TAB einger�ckt und nicht durch Leerzeichen! |
Make liest das Makefile und bestimmt f�r jedes target (angefangen mit dem ersten), ob das Kommando ausgef�hrt werden soll. Jedes target zusammen mit den prerequisites nennt man Regel.
# This Makefile builds Piets' and Jans' website, the potato-eaters. all: /home/piet/public_html/index.html /home/piet/public_html/offer.html /home/piet/public_html/index.html: header.html footer.html \ /home/jan/Docs/website/index.html { \ cat header.html /home/jan/Docs/website/index.html ;\ echo -n '<hr>Last modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > /home/piet/public_html/index.html /home/piet/public_html/offer.html: header.html footer.html \ /home/jan/Docs/website/offer.html { \ cat header.html /home/jan/Docs/website/index.html ;\ echo -n '<hr>Last modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > /home/piet/public_html/offer.html # the end
Hier haben wir drei targets, 'all', index.html und offer.html. Die einzige Funktion des targets 'all' ist die anderen beiden targets als prerequisites zu haben. Diese werden beide getestet, weil 'all' selbst kein Dateiname ist und 'all' damit immer ausgef�hrt wird. Sp�ter werden wir einen eleganteren Weg kennenlernen, um targets, die keine Dateinamen sind zu definieren).
Falls Kopf- und Fu�-Dateien ge�ndert w�rden, w�rden beide Seiten neu generiert. Falls Jan nur eine seiner Seiten modifiziert, wird auch nur eine neue Seite generiert. 'make' macht's.
Das Makefile hat ein Problem: es ist nicht so �bersichtlich. Zum Gl�ck gibt es verschiedene M�glichkeiten, die Sache einfacher zu machen.
variable = valueWir greifen auf den Wert einer Variablen mit dem Ausdruck $(variabele) zu. Im folgenden haben wir das in unser Makefile eingebaut:
# This Makefile builds Piets' and Jans' website, the potato-eaters. # Directory where the website is stored: TARGETDIR = /home/piet/public_html # Jans' directory: JANSDIR = /home/jan/Docs/website # Files needed for the layout: LAYOUT = header.html footer.html all: $(TARGETDIR)/index.html $(TARGETDIR)/offer.html $(TARGETDIR)/index.html: $(LAYOUT) $(JANSDIR)/index.html { \ cat header.html $(JANSDIR)/index.html ;\ echo -n '<hr>Last modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > $(TARGETDIR)/index.html $(TARGETDIR)/offer.html: $(LAYOUT) $(JANSDIR)/offer.html { \ cat header.html $(JANSDIR)/index.html ;\ echo -n '<hr>Last modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > $(TARGETDIR)/offer.html # the endEs ist eine Konvention, gro�e Buchstaben f�r Variablen zu benutzen. Jetzt ist es viel einfacher z.B Verzeichnise zu verschieben.
Was sollen wir machem, wenn wir noch mehr Dokumente haben. Das Makefile w�rde sehr lang. F�r jedes Dokument eine Regel wird auch wieder un�bersichtilch. Hier helfen Wildcards.
Falls `Pattern Rules' benutzt werden, kommt in der Regelzeile noch ein Feld hinzu.
Multiple targets: pattern : prerequisite prerequisite ... commandDas pattern ist ein Ausdruck der g�ltig f�r alle Targets ist. Ein Prozentzeichen dient dabei als Wildcard:
Ein Beispiel:
/home/bla/target1.html /home/bla/target2.html: /home/bla/% : % commandsMake vergleicht die zwei Targets mit dem pattern und macht daraus dann folgende Regeln:
/home/bla/target1.html: target1.html commands /home/bla/target2.html: target2.html commandsDas Prozentzeichen in `/home/bla/%' wird mit dem target `/home/bla/target1.html' zu `target1.html' und damit wird das prerequisite `%' zu `target1.html':
F�r unsere Webseite benutzen wir nun folgende Regel:
$(TARGETDIR)/index.html $(TARGETDIR)/offer.html: \ $(TARGETDIR)/% : $(JANSDIR)/% \ $(LAYOUT)Bleibt noch ein Problem: Wie benutzt man diese Variablen in Kommandos?
Die spezielle Variable $< enth�lt das erste prerequisite und die Variable $@ expandiert immer zum augenblicklichen target.
Mit diesen Variablen ist es m�glich, eine Regel mit Kommando zu verallgemeinern:
$(TARGETDIR)/index.html $(TARGETDIR)/offer.html: $(TARGETDIR)/% : \ $(JANSDIR)/% \ $(LAYOUT) { \ cat header.html $< ;\ echo -n '<hr>Last modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > $@Voilà! Das funktioniert nun f�r beide Dateien.
Hier ist nun unser komplettes Makefile:
# This Makefile builds Piets' and Jans' website, the potato-eaters. # Directory where the website is published: TARGETDIR = /home/piet/public_html # Jans' directory: JANSDIR = /home/jan/Docs/website # Files needed for the layout: LAYOUT = header.html footer.html # These are the webpages: DOCS = $(TARGETDIR)/index.html $(TARGETDIR)/offer.html # Please change nothing below this line;-) # ------------------------------------------------------------- all: $(DOCS) $(DOCS): $(TARGETDIR)/% : $(JANSDIR)/% $(LAYOUT) { \ cat header.html $< ;\ echo -n '<hr>Last modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > $@ # the endSo sollte es aussehen. Falls mehr Dokumente hinzukommen, ist das sehr leicht zu machen. Wir m�ssen nur die Variable DOCS �ndern.
Die Person, die mit dem Makefile arbeitet, sollte einfach sehen k�nnen, wie es arbeitet, ohne sich zu wundern, wie es wohl funktioniert.
TEXTS = index.html offer.html yetanotherfile.html # Please change nothing below this line;-) # ------------------------------------------------------------- DOCS = $(addprefix $(TARGETDIR)/,$(TEXTS)) all: $(DOCS) # and so onWas wir hier sehen, ist eine spezielle make Funktion. Anstelle einer Variablen kann man einen kompletten Ausdruck zwischen den Klammern benutzen. Mit solchen Ausdr�cken (vordefinierten Funktionen von make) kann man Text auf verschiedene Art und Weise modifizieren.
Die Funktion $(addprefix prefix,list) f�gt zu jedem Element in der Liste einen Prefix hinzu.
Die Elemente in der Liste m�ssen durch Leerzeichen getrennt sein.
Am Anfang haben wir schon erw�hnt, da� das target 'all' keine Datei namens 'all' erzeugt (die Regel enth�lt keine Kommandos). Was passiert jedoch, wenn diese Datei 'all' zuf�llig existiert und auch noch neuer als alle anderen Dateien ist...?
Es gibt eine einfache M�glichkeit make zu sagen, da� ein bestimmtes target ausgef�hrt werden soll und keine Datei erzeugt. Solch ein target markiert man als 'phony' (nicht wirklich). Das funktioniert so:
.PHONY: allNun sieht das ganze Makefile so aus:
# This Makefile builds Piets' and Jans' website, the potato-eaters. # Directory where the website is published: TARGETDIR = /home/piet/public_html # Jans' directory: JANSDIR = /home/jan/Docs/website # Files needed for the layout: LAYOUT = header.html footer.html # These are the names of the webpages: TEXTS = index.html offer.html yetanotherfile.html # Please change nothing below this line;-) # ------------------------------------------------------ DOCS = $(addprefix $(TARGETDIR)/,$(TEXTS)) .PHONY: all all: $(DOCS) $(DOCS): $(TARGETDIR)/% : $(JANSDIR)/% $(LAYOUT) { \ cat header.html $< ;\ echo -n '<hr>Last modification: ' ;\ date '+%A %e %B' ;\ cat footer.html ;\ } > $@ # the endSpeichere die Datei und vergi� sie! Lediglich TEXTS mu� vielleicht manchmal ge�ndert werden. Jetzt ist das Unterhalten der Webseite sehr einfach. Wir k�nnen sogar crontab benutzen und das Makefile t�glich ausf�hren.
Z.B ist die einfache Art und Weise, wie die Dokumente generiert werden, nicht fehlerfrei. Falls Jan versehentlich am Ende seiner Dateien </body></html> schreibt, werden einige Browser den Fu�teil von Piet nicht anzeigen. Man kann jedoch grep, perl oder tcl einsetzen, um das zu beheben.
Nat�rlich kann Jan auch einfach normale Textdateien schreiben und wir benutzen folgendes sed Kommando, um Paragraphen einzuf�hren (Leerzeilen durch <P> ersetzen):
sed -e 's/^\s*$/<p>/g'Weiterhin kann Jan seinen Text mit LyX schreiben und lyx2html kann benutzt werden, um daraus HTML zu machen. Deiner Phantasie sind unter Linux keine Grenzen gesetzt.
Wir haben uns noch keine Gedanken gemacht, wie Bilder behandelt werden sollen. Auch hier gibt es viele M�glichkeiten, aber das hat eigentlich nichts mit make zu tun.
Ich hoffe, es wurde klar, wie Make im Prinzip funktioniert und wie man viele Sachen mit einem guten Makefile vereinfachen kann.
Mit 'phony' targets (.PHONY: target), verschiedene Funktionen realisieren.Ein Beispiel ist die Konfiguration des Linuxkernels:
Tippt man make menuconfig erfolgt die Konfiguration des Kernels interaktiv. Mit make xconfig wird ein graphisches Konfigurationstool gestartet.
Beide targets haben eigentlich nichts mit dem Bau des Kernels zu tun. Sie erzeugen nur ein Benutzerinteface zur Konfiguration.
Hierzu brauchen wir ein Makefile mit folgenden Phony targets:
Auf diese Art kann man HTML aus einer Textdatei erzeugen und in einem weiteren Schritt das Layout dieser erzeugten HTML Datei verbessern:
TEMPLATE = layout1/Template1.txt /home/httpd/sales/sales.html: sales.html $(TEMPLATE) perl Scripts/BuildPage.pl -template $(TEMPLATE) $< > $@-new mv -f $@-new $@ sales.html: sales.txt aptconvert -toc $@ $<�berlege, wie die Dateien erneuert w�rden, wenn sich Template1.txt �ndert.
Ein Kommando, das als ersten Buchstaben ein '@' hat wird nicht auf dem Bildschrim ausgegeben.
target: prerequisite @cc -o target prerequisiteFalls ein Kommando mit '-' beginnt, wird make nicht abbrechen, wenn das Kommando einen Fehler erzeugt (z.B. L�schen eines nicht existenten Files):
.PHONY: clean clean: -rm -r $(tempdir)Um zu sehen, was bestimmte make Kommandos machen, z.B make install kann man make mit der Option -n laufen lassen. Damit wird nichts ausgef�hrt, sondern nur angezeigt:
wilbert@nutnix:~ > make -n install install -m 755 program /usr/local/bin install -m 644 program.1 /usr/local/man/man1 wilbert@nutnix:~ >
Falls man ein Dollarzeichen ($) nicht als Makevariable, sondern als Teil eines Dateinamens oder Shellkommandos braucht, mu� man ein Doppel-Dollarzeichen ($$) benutzen:
# A Makefile # Don't try this at home! :-) source = menu.txt help.txt target: $(source) for i in $(source) ;\ do \ if [ "$$i" = "menu.txt" ] ;\ then \ doThis $$i ;\ else \ doThat $$i ;\ fi ;\ done > targetMake wird vor der �bergabe der Kommandos an die Shell seine eigenen Variablen ersetzen und alle $$ in $ �ndern.
info makeAuch die GNOME und KDE Helpbrowser oder das n�tzliche tkinfo Programm k�nnen statt info benutzt werden.
Links:
Viel Spa�!