Forum: Compiler & IDEs Abhängigkeiten in make (avr-gcc)


von Hannes (Gast)


Lesenswert?

Hallo Leute,
mein make will nicht so wie ich. Ich möchte gern die Abhängigkeiten 
meiner c Quelltexte von den Headern automatisch ermitteln. Im Netz habe 
ich leider keine vollständige Anleitung und kein Beispiel gefunden, ist 
wahrscheinlich zu einfach...
Also jetzt von Anfang an:
Man kann make eine Regel angeben wie aus *.c *.o dateien gemacht werden:
1
%.o:%.c
2
    $(COMPILE) -c $< -o $@
Leider ist es hier nicht möglich die Abhängigkeiten von den *.h 
anzugeben - kann ja auch nicht sein, sie wären ja für alle *.c gleich. 
Die GNU Compiler haben deswegen die Option -MM welche die Abhängigkeiten 
der *.c Dateien ausgibt. Mann soll laut Internet dies machen:
1
depend:
2
  $(COMPILE) -MM $(CSOURCES) >.depend
3
4
-include .depend
Das findet man im Netz aber keine weiteren Anweisungen, was mich 
vermuten lässt, man schreibt es einfach mit ins Makefile, was ich auch 
tat.
Die Abhängigkeiten werden vom avr-gcc in die Datei .depend geschrieben 
und ins Makefile eingebunden. In der Datei steht so etwas:
1
main.o: main.c ../my_classes/typen.h ../my_classes/digital.h \
2
 ../my_classes/adc4433.h ../my_classes/adc.h
3
digital.o: ../my_classes/digital.c ../my_classes/typen.h \
4
 ../my_classes/digital.h
5
adc4433.o: ../my_classes/adc4433.c ../my_classes/adc.c \
6
 ../my_classes/adc.h ../my_classes/typen.h
Es sind die drei Objektdateien angeführt und hinter den Doppelpunkten 
stehen die Abhängigkeiten.

Dann kann man dies machen, aus dem Terminal kopiert:
1
h@acer2:/media/eee/GLOBALES/Projekte/_AVR/015_Eieruhr_2h_Schalter$ touch ../my_classes/typen.h 
2
h@acer2:/media/eee/GLOBALES/Projekte/_AVR/015_Eieruhr_2h_Schalter$ make
3
avr-g++ -I../my_classes -I. -mmcu=at90s4433 --define F_CPU=8000000UL -Wall  -ffunction-sections -Wl,--gc-sections -Os  -c main.c -o main.o
4
avr-g++ -I../my_classes -I. -mmcu=at90s4433 --define F_CPU=8000000UL -Wall  -ffunction-sections -Wl,--gc-sections -Os  -o main.bin main.o  ../my_classes/digital.o ../my_classes/adc4433.o 
5
rm -f main.hex main.eep.hex
6
avr-objcopy -j .text -j .data -O ihex main.bin main.hex
7
avr-size main.bin
8
   text    data     bss     dec     hex filename
9
    818       0       7     825     339 main.bin
10
h@acer2:/media/eee/GLOBALES/Projekte/_AVR/015_Eieruhr_2h_Schalter$
1.)touch typen.h. Davon sind alle drei c Dateien abhängig.
2.)make. Es sollte jetzt alles übersetzt werden - wird es aber nicht.
Was mache ich falsch?
Hier noch das Makefile:
1
SOURCES = main.c
2
FCPU = 8000000
3
DEVICE = at90s4433
4
#DEVICE = atmega8
5
6
AVRDUDE = avrdude -c usbasp -p $(DEVICE)
7
8
EASYAVRLIBDIR = ../my_classes
9
10
CFLAGS = -Wall  -ffunction-sections -Wl,--gc-sections -Os
11
CFLAGSDEB = -save-temps  -Wl,-Map,main.map
12
13
COMPILE = avr-g++ -I$(EASYAVRLIBDIR) -I. -mmcu=$(DEVICE) --define F_CPU=$(FCPU)UL $(CFLAGS) 
14
15
NEEDETLIBS = $(filter $(notdir $(basename $(wildcard $(addsuffix /*.c, $(EASYAVRLIBDIR))))),  $(shell sed -ne "s/^ *\# *include *[<\"]\(.*\)\.h[>\"]/\1/p" $(SOURCES)))  
16
OBJECTS =  $(addsuffix .o, $(basename $(SOURCES)))  $(addprefix $(EASYAVRLIBDIR)/, $(addsuffix .o,  $(NEEDETLIBS))) 
17
CSOURCES = $(addsuffix .c, $(basename $(SOURCES)))  $(addprefix $(EASYAVRLIBDIR)/, $(addsuffix .c,  $(NEEDETLIBS)))  
18
19
all:  main.hex
20
21
depend:
22
  $(COMPILE) -MM $(CSOURCES) >.depend
23
24
-include .depend
25
26
clean:
27
  rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.bin *.ii main.siz 
28
  rm -f *.o *.s main.disasm main.pre a.out $(EASYAVRLIBDIR)/*.o 
29
30
new: clean all
31
32
%.o: %.c
33
  $(COMPILE) -c $< -o $@
34
35
main.bin:  $(OBJECTS)
36
  $(COMPILE) -o main.bin $(OBJECTS)
37
38
main.hex:  main.bin
39
  rm -f main.hex main.eep.hex
40
  avr-objcopy -j .text -j .data -O ihex main.bin main.hex
41
  avr-size main.bin
42
43
44
45
debug:
46
  $(COMPILE) $(CFLAGSDEB) $(CSOURCES)
47
  $(COMPILE) $(CFLAGSDEB) -E main.c >main.pre
48
  avr-nm --size-sort -S main.bin >main.siz
49
  avr-objdump -d main.bin >main.disasm
50
  
51
flash:  all
52
  $(AVRDUDE) -U flash:w:main.hex:i

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

SOURCES hat nur main.c, d.h. beim Build des ELF / HEX wird von dort 
ausgegangen, was aber nicht zu digital.o etc. führt.

von Hannes (Gast)


Lesenswert?

Danke Johann L.! Ja, genau so ein dummer Fehler muss das sein. Aber ich 
habs noch nicht ganz geschnallt. Wie funktioniert make eigentlich?
Ich stelle mir das so vor: make will all herstellen dafür braucht es 
main.hex dafür main.bin und dafür $(OBJECTS) mit diesen Objects sucht 
das make die Zeile %.o: %.c und stellt die Objects wie dort angegeben 
her, wenn sie denn nicht aktuell sind.
In $(OBJECTS) sollten die drei Objekte stehen, stehen sie ja auch
1
main.bin:  $(OBJECTS)
2
  $(COMPILE) -o main.bin $(OBJECTS)
dies ist für die zweite Ausgabezeile des Compilers (eigentlich Linkers) 
verantwortlich und da sind sie aufgeführt.

Das Makefile macht folgendes: Es schaut in alle SOURCES und sucht die 
#includes. Gibt es das includierte .h in meinem Libverzeichnis als .c 
wird dieses .c über NEEDETLIBS zusammen mit SOURCES in die CSOURCES und 
OBJECTS aufgenommen und sollen mit übersetzt werden.
Wenn ich eine meiner Klassen in einem Programm includiere such das make 
sich automatisch die Quelltexte und bindet sie ein.

von Stefan E. (sternst)


Lesenswert?

Dein Problem dürften die Pfade sein. Ein Teil der Objekt-Dateien liegt 
ja in einem anderen Verzeichnis:
1
avr-g++ ... ../my_classes/digital.o ../my_classes/adc4433.o
Die generierten Abhängigkeiten sind jedoch ohne Pfad:
1
digital.o: ...
2
adc4433.o: ...
Und "digital.o" und "../my_classes/digital.o" sind nun mal zwei 
verschiedene Dinge.

von hannes (Gast)


Lesenswert?

Das ist ja ein Ding, da hast Du recht. Irgendwie bin ich jetzt ganz 
verwirrt, wiso funktioniert das eigentlich sonst immer? Aber ich sehe 
das genauso wie Du. Nur die Reaktion passt nicht so ganz, wenn das Ziel 
nicht existiert, wegen das falschen Pfades, müsste das make den Compiler 
immer anwerfen, auch wenn das richtige Ziel schon aktuell ist.
Oder wie, oder was? ich bin wirklich etwas verwirrt aber teste das 
nachher mal.
Danke auf jeden Fall.

von Stefan E. (sternst)


Lesenswert?

hannes schrieb:
> Nur die Reaktion passt nicht so ganz, wenn das Ziel
> nicht existiert, wegen das falschen Pfades, müsste das make den Compiler
> immer anwerfen, auch wenn das richtige Ziel schon aktuell ist.

Nein, denn das falsche Ziel kommt ja nie zum Zuge.
Wenn nirgendwo sonst im Abhängigkeiten-Baum ein digital.o benötigt wird, 
dann versucht Make auch nicht eines zu erstellen, und interessiert sich 
damit auch nicht die Bohne dafür für dessen Abhängigkeiten.

von Hannes (Gast)


Lesenswert?

Na das erklärt einiges, nicht nur das beschriebene Problem. Ich habe 
jetzt händisch die Pfade nachgetragen und siehe da, es macht was es 
soll. Vielen Dank Stefan!

Die Abhängigkeitsdatei stammt vom Compiler. Kann man den überreden das 
er gleich den Pfad mit hinschreibt? Oder gibt es eine andere Lösung?

von Stefan W. (dl6dx)


Lesenswert?

Vielleicht noch als Anregung:

Bei komplexeren Projekten ist es nicht unüblich, je Verzeichnis ein 
Makefile vorzusehen.
Das "Master-Makefile" enthält dann je Verzeichnis einen Targeteintrag, 
dessen buid rule in etwa so aussieht:
1
cd $verzeichnis ; make $mastertarget ; cd ..
$mastertarget ist entweder ein Pseudo-Target wie "all" oder "clean" oder 
eine "echte" Target-Datei.

Grüße

Stefan

von Hannes (Gast)


Lesenswert?

Bei mir geht es im Grunde um eine Library, die ich als Quellcode halte 
weil ich Probleme bei einem Prozessorwechsel befürchte. Im 
Verzeichnisbaum wird die Lib dann immer über oder neben dem 
Projektverzeichnis stehen.
Ich habe den Verdacht, dass ich etwas denke, was man so nicht denkt und 
der Compiler deswegen, aus meiner Sicht, komische Dinge tut:
Der Compileraufruf ist für die Erzeugung der Abhängigkeiten und der 
Objekte identisch, bis auf das -MM natürlich. Der Compiler wird mit dem 
Pfad zum Quellcode aufgerufen und er legt das Objekt in dem selben Pfad 
ab. Soweit Logisch. Erzeugt er dagegen Abhängigkeiten, löscht er den 
Pfad zum Objekt (finde ich komisch) - aber nicht zu den .h - das ist mir 
gänzlich unverständlich, weil nichtmal konsistent.

von Malte (Gast)


Lesenswert?

Hannes schrieb:
> Der Compileraufruf ist für die Erzeugung der Abhängigkeiten und der
> Objekte identisch, bis auf das -MM natürlich.

Nein, ist er nicht. Das -o in der Regel für den Compilerlauf bestimmt 
den Namen (einschließlich Pfad) des Ziel der Kompilierung. Beim 
depend-Target gibt es diese Spezifikation nicht. Der Compiler leitet den 
Zielnamen einfach von der Quelldatei ab - und nimmt die einfachste 
Variante.

Um Schock *Horror* mal aus der Dokumentation zu zitieren wie er dies 
macht - ja, lesen bildet :-)

> Unless specified explicitly (with -MT or -MQ), the object file name
> consists of the name of the source file with any suffix replaced with
> object file suffix and with any leading directory parts removed.

"with any leading directory parts removed". Ist doch eindeutig.

Die Lösung ist in der Dokumentation auch angedeutet "Unless specified 
explicitly (with -MT or -MQ)". Angedeutet, weil man sich mit den 
Make-Stringfunktionen und eingebauten Variablen das richtige Argument 
basteln muss.

von Hannes (Gast)


Lesenswert?

Huh, da hast Du aber deutliche Worte gefunden Malte.
Aber beschäftigen wir uns zunächst mit dem Vergleich unserer Personen:
1. Du kannst mir etwas erklären. (stimmt wahrscheinlich, habe mich mit 
deiner Antwort noch nicht tiefer beschäftigt.) Punkt für dich.

2. Du kannst lesen und bist gebildet. Eindeutig Punkt für dich.

3. Du kannst Englisch. Punkt für dich.

4. Du weist was eindeutig ist - na, Doppelpunkt für dich - nein, die 
Eindeutigkeit wurde ja nochmals wiederholt ohne sie zu übersetzen oder 
gar den Sinn in eigenen Worten wiederzugeben. Das ist ja Doppel doppel 
also vier Punkte.

Das sind also 0 Punkte für mich und 6 Punkte für dich. Du darfst mich 
Wurm nennen.


:-) (Wenn ich die richtige Antwort kriege sage ich warum ich grinse)

--------------------------------------------
Ich hatte ein paar Jahre Auszeit vom AVR und von diesem Forum, nun habe 
ich beides wiederendeckt und es macht mir Spaß. Aber ich hatte bald den 
Eindruck das der Ton hier im Forum rauer geworden ist, was dem Spaß 
abträglich ist.
Das ist doch unsere Sandkiste, wenn wir uns die Schäufelchen um die 
Ohren hauen wird die Sandkiste bald leer sein oder die Insassen 
vergreisen, weil keine neuen Leute mehr kommen. Ich selbst bin 
wankelmütig ob ich bleiben soll, denn ich bin zum Spaß hier und es gibt 
hier viele nette und kompetente Leute mit denen es wirklich Spaß macht.
Aber soll ich hier ein Projekt vorstellen um mich somit dem rauen Wind 
auszusetzen? Ich warte noch ab. Bitte macht dieses Forum nicht kaputt 
indem die Leute runtergeputzt werden.
Bringt ja auch nichts, wenn hier nur Idioten sind warum seid ihr hier? 
Wenn man zu dem Schwachsinn nichts mehr sagen kann, warum dann 
Antworten? Solche Punktespiele von oben funktionieren nicht, weil ein 
Leser das Punktesystem so nicht aufstellt. Richtig viele Punkte bekommt 
man für gute Erklärungen, richtig Kompetent ist der, der einen 
Sachverhalt so erklären kann das jeder Depp das versteht. Das merkt auch 
der Leser und gibt richtig Punkte.
Und mal ganz ehrlich, worum geht es hier überhaupt? Ich fand meine Frage 
spannend, sie betrifft aber nur mein Hobby ist also nicht lebenswichtig. 
Die Lösung, ja mal sehen, wenn sie interessant ist werde ich die 
verwenden, wenn nicht - wie lange braucht ein GHz Prozessor im 
schlechtesten Fall um 8 kB Code zu erzeugen? Im Zweifel ist sogar das 
make überflüssig. Es geht doch um nichts wichtiges, da können wir auch 
nett zueinander sein.
Das hab ich geschrieben weil mir dieses Forum am Herzen liegt  und ich 
hoffe das, dass Klima wieder besser wird. Ich tauche dann erstmal wieder 
ab.
Hannes

von Malte (Gast)


Lesenswert?

Es sind Typen wie du, warum man die Lust verliert jemandem was zu 
erklären.

von Fred (Gast)


Lesenswert?

Stefan Wagner schrieb:
> Bei komplexeren Projekten ist es nicht unüblich, je Verzeichnis ein
> Makefile vorzusehen.

"recursive make considered harmful".

Just say "no".

von Stefan W. (dl6dx)


Lesenswert?

Fred schrieb:
> "recursive make considered harmful"

Interessante Arbeit. Kannte ich noch nicht.

Grüße

Stefan

Ach ja: Wer's lesen will:
http://aegis.sourceforge.net/auug97.pdf

: Bearbeitet durch User
von Frank Gerlach (Gast)


Lesenswert?

Liegt es evtl. einfach daran, dass die .depend-Datei nicht die korrekte 
Endung *.obj sondern *.o enthaelt. Der g++ ist sich selbst nicht sicher, 
ob er *.obj oder *.o erzeugt, wie es scheint :-(

Das sehe ich bei mir nämlich auch gerade.

schnelle (vllt. nicht perfekte) Lösung:
sed "s/.o: /.obj: /g" .depend > x
mv x .depend

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.