Moin,
um bei der VHDL-Entwicklung mit GHDL nicht jede Zeile immer wieder
aufrufen zu müssen, habe ich mich mal ein bisschen mit Make beschäftigt
und mir eine Makedatei geschrieben.
Ich weiß, dass das nicht ideal ist, weil ich alle Dateien in einer Regel
übersetze, aber das ist jetzt nicht die Frage.
Die Frage ist, ob die Namen der Regeln/Ziele, in diesem Fall 'Testbench'
eine Bedeutung haben, oder ob ich jeden beliebigen nehmen kann. Ich habe
es ausprobiert und es funktioniert auch mit anderen Namen, aber ist das
nur hier so oder grundsätzlich?
Beispiele sind immer in der Art
1
prog: foo.o bar.o
2
$(LD) -o prog foo.o bar.o
3
4
foo.o: foo.c
5
$(CC) -c foo.c
6
7
bar.o: bar.c
8
$(CC) -c bar.c
(Von Wikipedia: Make)
Daher dachte ich, dass die Regel so heißen muss, wie die erzeugte Datei.
Haben die Namen der Ziele also etwas mit den Namen der erzeugten Dateien
zu tun oder sind das nur Bezeichner und man kann sie beliebig nennen?
Da Make wahrscheinlich hauptsächlich von Programmierern benutzt wird,
stelle ich die Frage hier.
Es gibt 2 Arten von Zielen.
In einem normalen Makefile findest du Ziel, die du von aussen aufrufst,
wie "make all" oder "make dist" oder "make clean". Die kannst du nennen,
wie du willst.
Und dann gibt es die internen Ziele. Bevor Make das Ziel "prog"
erstellen kann, muss es zunächst die Ziele "foo.o" und "bar.o"
erstellen. Nahezu alle dieser internen Ziele musst du genau so nennen,
wie die Datei. (Make schaut, ob eine Datei dieses Namens bereits
existiert, und ob sie neuer ist, als die Ziele, von denen diese Datei
abhängt).
Dussel schrieb:> Haben die Namen der Ziele also etwas mit den Namen der erzeugten Dateien> zu tun oder sind das nur Bezeichner und man kann sie beliebig nennen?
Das Ziel einer Regel ist immer ein Dateiname.
Wenn du also folgende Regeln schreibst:
1
all: Testbench prog
2
3
hello:
4
echo "Hello, world!"
5
6
...
... dann versucht "make hello" , die Datei "hello" zu erstellen, indem
das echo ausgeführt wird; und "make all" versucht, die Datei "all" zu
erstellen, indem zuerst die beiden Abhängigkeiten erstellen werden, und
dann die Kommando-Liste der Regel selbst ausgeführt wird (die Liste ist
leer).
In beiden Fällen gibt es die Ziel-Datei dann nicht. Wenn du "make hello"
noch einmal aufrufst, wird die Meldung noch einmal ausgegeben. Wenn du
"make all" noch einmal aufrufst, werden die drei Abhängigkeiten neu
erstellt, falls notwendig.
Aber wenn es im aktuellen Verzeichnis Dateien mit den Namen "all" oder
"hello" gibt (die neuer sind als ihre Abhängigkeiten), dann würde Make
die Kommandos nicht mehr ausführen. Um dieses Problem zu vermeiden, hat
GNU Make die Direktive .PHONY, mit der man ein Ziel festlegen kann, das
keine Datei ist:
https://www.gnu.org/software/make/manual/make.html#Phony-Targets
Ach, jetzt habe ich es verstanden, glaube ich.
Wenn die Ziele in der Datei beliebig nenne, funktioniert es trotzdem,
aber es erkennt dann nicht mehr, was aktuell ist.
Ich habe die Datei ein bisschen umgeschrieben:
Beim ersten wird erkannt, wenn die Dateien noch aktuell sind, und nichts
mehr ausgeführt, beim zweiten werden bei jedem Aufruf die Anweisungen
nochmal ausgeführt.
Mich hatte irritiert, dass es in beiden Fällen geklappt hat. Deshalb sah
es für mich so aus, als seien die Namen egal.
Danke.
Noch einer schrieb:> Es gibt 2 Arten von Zielen.>> In einem normalen Makefile findest du Ziel, die du von aussen aufrufst,> wie "make all" oder "make dist" oder "make clean". Die kannst du nennen,> wie du willst.>> Und dann gibt es die internen Ziele. Bevor Make das Ziel "prog"> erstellen kann, muss es zunächst die Ziele "foo.o" und "bar.o"> erstellen. Nahezu alle dieser internen Ziele musst du genau so nennen,> wie die Datei. (Make schaut, ob eine Datei dieses Namens bereits> existiert, und ob sie neuer ist, als die Ziele, von denen diese Datei> abhängt).
Hier stimmt einiges, aber nicht ganz.
Prinzipiell ist jedes Ziel in make eine Datei, welche es zu erstellen
gilt.
OB diese Zieldatei (erneut) erstellt werden muss, hängt von den
Zeitstempel der Zieldatei selbst und deren Abhängigkeiten ab: ist die
Zieldatei zwar vorhanden jedoch älter als ihre Abhängigkeiten oder
existiert sie nicht, so werden die dazugehörigen Befehle ausgeführt (das
WIE).
Ziele wie "clean" welche keiner Datei entsprechen, nennt man phony und
sollten mit diesem Schlüsselwort ausgezeichnet werden. (bei "clean"
werden typischerweise *.o Dateien gelöscht, bei "download" o.ä. wird
eine Binärdatei zum Zielgerät übertragen)
Ziele wie "all", "dist" o.ä. können für mehrere Dateien auf einmal
stehen; das wird mit Variablen realisiert, deren Werte Listen von
Dateien sind. (und/oder mit phony)
JEDES der Ziele kann aufgerufen werden.
Nebst den weiter oben aufgeführten namentlicher Nennung jeder einzelnen
Datei (was in sinnloser Fleißarbeit ausartet) kennt make auch
raffinierte Wildcards, also Musterorientierte Regeln und zugehörige
Funktionen zu Manipulation von Zeichenketten (insbes. Pfad- und
Dateinamenbestandteile).
Die Auflösung solcher Musterorientierten Regeln produzieren make
-interne Regeln und Ziele, welche zwar nur für die Dauer des gerade
laufenden make -Programmlaufes existieren, jedoch genauso gültige
Ziele für einen Aufruf sind.
- - -
Ein kunstgerecht geschriebenes Makefile enthält sehr wenig Redundanz:
z.B. wird nur eine (ggfs. mehrteilige) Liste von Quelldateien geführt
und gepflegt (nein, die kann make nicht erraten... ausserdem werden
durchaus noch welche von Hilfsmittel wie z.B. flex, bison uva. erst
noch erzeugt, natürlich via weitere make -Regeln... ) die Liste von
*.o-Dateien entsprechend davon "rausgerechnet", es produziert jedoch
entsprechen viele interne Regeln sodass make die totale UND
detaillierte Übersicht ALLER Abhängigkeiten hat.
Hat make diese Übersicht, kann es mittels Kommandozeilenschalter
"--jobs n " angemessen bis beliebig viele Teilbereiche parallel
Kompilieren
In Projekte von "ordentlicher" Größe (ab hunderte von Quellcodedateien)
zeichnen sich kunstgerecht geschriebene Makefiles dadurch aus dass sie
zwar bei Start "ein wenig Nachdenken" bevor die Kompileraufrufe
loslegen, dann aber beim Wechsel von "make clean; make all -j 1"
(default) auf "make clean; make all -j 16" tatsächlich die
Auslastungsanzeige ALLER CPU-Cores "an die Decke hochjagen" und die
Buildzeit des Projektes durchaus um 90% verkürzen.
(unsachgemäss, plump geschriebene Makefiles können da entsprechend
nicht zaubern...)
PS: "Datei" steht im ganzen Text für ein beliebiger Eintrag im
Dateisystem, also stellvertretend für echte Dateien, (Sym)Links,
Verzeichnisse, usw.