Forum: Mikrocontroller und Digitale Elektronik Makefilefragen


von Bernd (Gast)


Lesenswert?

Hi,

ich befasse mich gerade mal mit dem Thema Makefiles anhand eines bereits 
vorhandenen. Leider sind mir noch nicht alle Details
klar.
Zu Beginn werden im Makefile die Verzeichnisse definiert - z.B. OBJ.
Anschließend kommen einige "export" Sachen wie "export MNAME".

Und zum Schluss kommen die einzelnen make Befehle die auf der 
Commandozeile eingegeben werden können. Als erster Befehl steht
im Makefile "top", welcher stets aufgerufen wird, wenn nur "make" in der 
Commandozeile eingegeben worden ist. Dieser Befehl sieht
folgendermaßen aus:
1
.PHONY: top all mkdirs clean 
2
3
export MNAME
4
5
top: mkdirs all
6
all clean archieve link compile: $(OBJ)
7
  $(MAKE) -C $(OBJ) -f $(BUILD)/comp.mk $@
8
9
$(MNAME): $(OBJ)
10
  $(MAKE) -C $(OBJ) -f $(BUILD)/comp.mk MNAME=$@
11
12
$(OBJ):
13
  mkdir -p $(OBJ)
14
  @echo "skip: *" > $(OBJ)/.nsr

a) lege ich richtig, dass "mkdirs all" zwei weitere make commands sind, 
die für das comp.mk benötigt werden bzw. dadurch dort entsprechende 
Anweisungen durchgeführt werden? Was bedeutet in diesem Zusammenhang 
allerdings das .PHONY


b) $(OBJ):

Zuerst wird das Verzeichnis angelegt: mkdir -p $(OBJ). Wieso schreibt 
man das hier aber mit "all clean archieve..: $(OBJ)? und nicht
einfach "mkdir -p $(OBJ)". Und den Sinn der zweiten Zeile mit "/.nsr" 
verstehe ich leider noch nicht.

c) MNAME=$@

Aus welcher Zeile sieht man, dass MNAME = all gesetzt wird, da im 
Terminal $(MAKE) -C $(OBJ) -f $(BUILD)/comp.mk all steht.

Gruß
Bernd

von Karl H. (kbuchegg)


Lesenswert?

es gibt zu make auch jede Menge Doku im Web. Lies sie.

Ausgangspunkt von make sind 'Regeln'
Eine Regel beschreibt
  wer hängt von wem an und welche Aktionen sind auszuführen, damit
  'wer' neu erzeugt wird.

Die allgemeine Regel sieht so aus

wer:  wem
   Aktion
   Aktion


Wichtig dabei: die 'Aktionen' sind jeweils mit einem Tab eingerückt.

Wenn du make per Commandozeile aufrufst, dann gibts du da keinen Befehl 
mit, sondern du teilst make mit bei welcher Regel es anfangen soll, sie 
auszuwerten.

Schreibst du zb ins make

test.exe:  test.obj
   link test.obj

dann bedeutet das: Die Datei test.exe hängt von test.obj ab. Wenn 
test.obj ein neueres Filedatum hat als test.exe dann wird der 
Betriebssystem-Commandline das Kommando "link test.obj" übergeben und 
die Ausführung dieses Kommandos erzeugt dann hoffentlich test.exe neu.

Jetzt kann natürlich auch test.obj von etwas abhängen. Zb von test.c


test.exe:  test.obj
   link test.obj

test.obj: test.c test.h
   compile test.c

gleiches Spiel: test.obj hängt von test.c ab UND von test.h
Trägt eine der beiden Dateien ein neueres Datum als test.obj, dann wird 
"compile test.c" an die Betriebssystem Commandline übergeben, welches 
dann hoffentlich test.c neu compiliert, welches ein neues test.obj 
ergibt, was dann wieder dazu führt, dass test.obj neuer ist als test.exe 
und daher wird dann auch test.exe neu erzeut.

Normalerweise fängt make bei der Abarbeitung und beim Aufspannen der 
Regeln mit der ersten Regel an, die es findet. Aber: Man kann auch auf 
der Command line mitgeben, mit welcher Regel es anfangen soll.

make macht nichts anderes als die Zeiteinträge von Dateien zu 
vergleichen und wenn ein abhängiges File älter ist als eines von dem es 
abhängt, dann werden Anweisungen an die Commandline des Betriebssystems 
übergeben.


Und der Rest steht in der Doku zu make. Lies sie.

von Bernd (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Und der Rest steht in der Doku zu make. Lies sie.

erst einmal vielen Dank für deine Antwort. Natürlich hab ich bereits ein 
paar Dokumente zu Makefile durchgelesen, aber bis man es begreift dauert 
es halt ne gewisse Zeit.

von Karl H. (kbuchegg)


Lesenswert?

Bernd schrieb:
> Karl Heinz Buchegger schrieb:
>> Und der Rest steht in der Doku zu make. Lies sie.
>
> erst einmal vielen Dank für deine Antwort. Natürlich hab ich bereits ein
> paar Dokumente zu Makefile durchgelesen, aber bis man es begreift dauert
> es halt ne gewisse Zeit.

Dann solltest du erst mal einfache Makefiles studieren.

Und ich hab noch vergessen: Du musst auch die Command-Schnittstelle (die 
'Shell') deines Betriebssystems studieren. Denn make an sich führt 
überhaupt keine Aktionen aus. Es übergibt einfach nur einen Text an 
diese Shell und die Shell führt diese aus. make macht gerade noch 
Makro-Substitution, ersetzt also einen Text durch einen anderen Text. Um 
also zu ergründen, was

  @echo "skip: *" > $(OBJ)/.nsr

macht, brauchst du 2 Dinge

* durch welchen Text wird $(OBJ) von make ersetzt? Irgendwo vorher im
  makefile steht
  OBJ = irgendwas

  d.h. in dieser Zeile wird $(OBJ) durch 'irgendwas' ersetzt
  neuer Text:
   @echo "skip: *" > irgendwas/.nsr

* du musst wissen, was die Shell jetzt mit diesem Kommando macht.
  Im konkreten sieht das nach einer Windows-Shell aus, @echo gibt
  einfach den nachfolgenden Text aus und der '>' ist die sog. Output
  Redirection, die die Ausgabe eines Programms in eine Datei umleitet.
  Das hat aber mit 'make' im eigentlichen Sinne überhaupt nichts mehr
  zu tun, sondern
  a) mit den Möglichkeiten der Shell
  b) der Fragestellung, warum der Makefile-Schreiber unbedingt den Text
     "skip: *" in der Datei 'irgendwas/.nsr' stehen haben will. Könnte
     zb sein, dass irgendein anderes Programm nach genau dieser Datei
     sucht, und abhängig vom Inhalt irgendwas macht oder nicht macht.

von Malte S. (maltest)


Lesenswert?

Bernd schrieb:
> top: mkdirs all
> all clean archieve link compile: $(OBJ)
>
>   $(MAKE) -C $(OBJ) -f $(BUILD)/comp.mk $@
> $(OBJ):
>   mkdir -p $(OBJ)
>   @echo "skip: *" > $(OBJ)/.nsr


Um das mit deinem neuen Wissen einmal genauer anzusehen:

> top: mkdirs all

das Toplevel-Target (das statt "top" auch jeden anderen Namen haben 
könnte, entscheidend ist nur, dass es das erste Target im Makefile ist), 
ist abhängig von "mkdirs" und "all"

Denn zusätzlich zu den reinen Dateizeitstemepvergleichsregeln kann man 
make auch solche unterschieben, zu denen es gar keine Dateien gibt.
Dieser Umstand wird hiermit make sauber mitgeteilt:

> .PHONY: top all mkdirs clean

Das ist nicht strikt notwendig, aber guter Stil, da es make dabei hilft, 
diesen Sonderfall sauber zu behandeln. Die Klärung der Abhängigkeiten 
wird beschleunigt und vor allem vermeidet man so Probleme, falls es 
wirklich mal eine Datei dieses Namens geben sollte. Die wird dann von 
make ignoriert.

Also "top" ist abhängig von "mkdirs" und "all", die ebenfalls nur Namen 
sind. Jedes Mal wenn make "top" "erstellen" soll, werden zuerst "mkdirs" 
und "all" erstellt, also die zur Erstellung dieser Targets definierten 
Befehle an die Shell übergeben.

> all clean archieve link compile: $(OBJ)

Alles was links des Doppelpunkts genannt ist, ist von $(OBJ) abhängig. 
Also sobald make die Regeln zur Erstellung von "all", "clean", 
"archive", "link" oder "compile" abarbeitet, wird zuerst überprüft, ob 
$(OBJ) aktuell, d.h. neuer als seine Anhängigkeiten ist.

Dass make eines dieser Targets erstellen "möchte" kann verschiedene 
Ursachen haben:

* make wurde explizit dazu aufgefordert z.B. durch
  make clean

* make wurde ohne Nennung eines Targets aufgerufen und erstellt das 
Toplevel-Target:
  make

* das Target steht in der Abhängigkeitenliste eines anderen Targets, 
dass erstellt werden soll.

Bernd schrieb:
> Zuerst wird das Verzeichnis angelegt: mkdir -p $(OBJ). Wieso schreibt
> man das hier aber mit "all clean archieve..: $(OBJ)? und nicht
> einfach "mkdir -p $(OBJ)".

Ich hoffe das o.g. hilft zum Verständnis dieser Konstrukte.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.