Forum: Compiler & IDEs ARM-GCC: makefile


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,
die Frage mal banal klingen, ich sehe aber so langsam den Wald vor 
lauter Bäumen nicht mehr.

Ich schreibe momentan eine Firmware für einen STM32F103RB in der CooCox 
IDE. Ich glaube zwar nicht, daß die Welt auf mein Projekt gewartet hat - 
will es aber dennoch als Open Source veröffentlichen (ob als warnendes 
Beispiel oder als Inspiration kann sich ja jeder selbst aussuchen). Dazu 
gehört natürlich auch ein ordentliches makefile.

"Nicht einfacher als das", habe ich gedacht. Immerhin sind die 
Projekteinstellungen von CooCox ja eine gut lesbare XML-Datei, die sich 
problemlos mit einem Script in ein makefile umwandeln lassen sollte.

Und jetzt kommt das Problem: Welches Makefile eignet sich als Template? 
Sucht man nach "STM32F10x" und "makefile", ergeben sich schon viele 
Treffer. Aber welches nimmt man? Der folgende Treffer ( 
https://gist.github.com/mcufreaks/5224642 ) sah zuerst sehr 
vielversprechend aus- ich verstehe nur nicht, wo die Projektdateien 
hinkommen sollten.

Das "GNU-make-Handbuch" habe ich hier. Aber irgendwie ist das ungefähr 
wie fremden Quelltext zu lesen, wenn man in der Programmiersprache noch 
nicht über das "Hallo Welt" hinausgekommen ist.

Der langen Frage kurzer Sinn: Kann mir jemand ein lesbares oder 
zumindest funktionierende Makefile für diese Plattform empfehlen?

Viele Grüße
W.T.

: Bearbeitet durch User
von Lukas K. (carrotindustries)


Lesenswert?

Ich hatte in Beitrag "Entwickeln für STM32 ohne IDE" meine 
Makefile für die STM32F4 vorgestellt, wenn du Linker-Script, 
Compilerflags und CMSIS nach den Beispielen für dem F1 umbaust, sollte 
die Makefile auch damit funktionieren.

von Walter T. (nicolas)


Lesenswert?

Hallo Lukas,
das sieht auf den ersten Blick schon recht gut aus. Aber welchen Zweck 
erfüllt das python-Script?

von Make(file)er (Gast)


Lesenswert?

Also ich habe hier mal einen Makefile für das STM32F4. Wenn du das nun 
nach deinem Beispiel bei Github umbaust, müsste das funktionieren. 
Einzig, was mich auch etwas gewundert hat(es ist im Makefile nirgends zu 
finden), ist dass die Source-Dateien im interordner src liegen.

MAKEFILE

# put your *.o targets here, make should handle the rest!

SRCS = delay_taster.c system_stm32f4xx.c

# all the files will be generated with this name (main.elf, main.bin, 
main.hex, etc)

PROJ_NAME=main

# that's it, no need to change anything below this line!

###################################################

CC=arm-none-eabi-gcc
OBJCOPY=arm-none-eabi-objcopy

CFLAGS  = -g -O2 -Wall -Tstm32_flash.ld
CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -mthumb-interwork
CFLAGS += -mfloat-abi=hard -mfpu=fpv4-sp-d16

###################################################

vpath %.c src
vpath %.a lib

ROOT=$(shell pwd)

CFLAGS += -Iinc -Ilib -Ilib/inc
CFLAGS += -Ilib/inc/core -Ilib/inc/peripherals

SRCS += lib/startup_stm32f4xx.s # add startup file to build

OBJS = $(SRCS:.c=.o)

###################################################

.PHONY: lib proj

all: lib proj

lib:
  $(MAKE) -C lib

proj:   $(PROJ_NAME).elf

$(PROJ_NAME).elf: $(SRCS)
  $(CC) $(CFLAGS) $^ -o $@ -Llib -lstm32f4
  $(OBJCOPY) -O ihex $(PROJ_NAME).elf $(PROJ_NAME).hex
  $(OBJCOPY) -O binary $(PROJ_NAME).elf $(PROJ_NAME).bin

clean:
  rm -f *.o
  rm -f $(PROJ_NAME).elf
  rm -f $(PROJ_NAME).hex
  rm -f $(PROJ_NAME).bin

von Walter T. (nicolas)


Lesenswert?

OK, das makefile von Lukus scheint sich auf andere Makefiles, die beim 
CMSIS beiliegen sollten, die ich aber nicht habe, zu verlassen.

Also probiere ich erst einmal bei dem anderen mein Glück.

Das schlägt allerdings (nachdem man die vom Forum zerstörten Tabs 
wiederhergestellt hat) bei der Zeile "make -C lib" fehl mit der 
Fehlermeldung: make: *** lib: No such file or directory.  Schluss.

Allerdings bin ich mir auch noch nicht sicher, was mit den beiden 
vpath-Zeilen gemeint ist.

von Lukas K. (carrotindustries)


Lesenswert?

Walter Tarpan schrieb:
> Hallo Lukas,
> das sieht auf den ersten Blick schon recht gut aus. Aber welchen Zweck
> erfüllt das python-Script?

Das sign.py?
Äh, ja hätte man vielleicht im README erwähnen sollen…
Ich hatte mal damit experimentiert, die Hauptapplikation im Flash nach 
hinten zu verschieben, um im ersten Flash-Sektor mithilfe der von 
sign.py erzeugten Prüfsumme die Applikation verifizieren zu können und 
bei Fehlschlag in den DFU-Bootloader zu fallen, sodass das Gerät — 
soweit die Theorie — 'unbrickbar' wird.

In der aktuellen Makefile wir sign.py aber so aufgerufen, dass es 
garnichts macht. main.bin.signed ist also mit main.bin identisch.

Das stm32_flash.py bedient OpenOCD um die main.bin zu flashen.

EDIT:
Walter Tarpan schrieb:
> OK, das makefile von Lukas scheint sich auf andere Makefiles, die beim
> CMSIS beiliegen sollten, die ich aber nicht habe, zu verlassen.

Nene, das sind Makefiles, die in epm-Paketen (siehe 
https://github.com/carrotIndustries/epm und 
https://github.com/carrotIndustries/epm-availables ) vorhanden sind. 
Ziel war es den Komfort, den man von den ganzen neumodischen 
Web-Frameworks und Sprachen (node.js, python, ruby) hinsichtlich 
Paketmanagement halbwegs in die Embedded-Welt zu tragen.

Da du oben was von CooCox schriebst, rate ich mal, dass du auf Windows 
arbeitest, keine Ahnung inwieweit der epm damit auf die Nase fällt… (nie 
getestet)

: Bearbeitet durch User
von Walter T. (nicolas)


Angehängte Dateien:

Lesenswert?

Lukas K. schrieb:
> epm-Paketen (siehe
> https://github.com/carrotIndustries/epm und
> https://github.com/carrotIndustries/epm-availables ) vorhanden sind.
> Ziel war es den Komfort, den man von den ganzen neumodischen
> Web-Frameworks und Sprachen (node.js, python, ruby) hinsichtlich
> Paketmanagement halbwegs in die Embedded-Welt zu tragen.

OK, mit Paket-Managern kenne ich mich zwar nicht aus. Aber ich glaube, 
den Komfort brauche ich auch nicht- schließlich geht es um ein einziges 
Makefile.

Ich habe mal ein Mini-Projekt gemacht, das sich mit CooCox bauen läßt, 
um nicht die Übersicht zu verlieren.

Was mir auffällt, daß CooCox bei seinem Build (Konsolenausgabe siehe 
Anhang) gar kein *.s-Startup-File hat. (Ich habe die Konsolenausgabe zur 
besseren Lesbarkeit etwas gekürzt - Sprich: Pfade gekürzt und 
umgebrochen.)

Eigentlich wundert mich, daß der Konsolenaufruf so kurz ist. Oder 
enthält mir da CooCox etwas vor?

von Make(file)er (Gast)


Lesenswert?

Walter Tarpan schrieb:
> Das schlägt allerdings (nachdem man die vom Forum zerstörten Tabs
> wiederhergestellt hat) bei der Zeile "make -C lib" fehl mit der
> Fehlermeldung: make: *** lib: No such file or directory.  Schluss.

Das liegt daran, dass du da im Makefile auf bei dir nicht vorhandene 
Verzeichnisse zugreifen will.
Also bei mir ibt es die Verzeichnisse:
src; lib; inc
Die Namen sind ja selbsterklärend ;)
Für genauere Infos musst su hier schauen: 
https://github.com/jeremyherbert/stm32-templates Und da im Unterordner 
stm32f4.
für vpath musst hier 
schauen:http://www.gnu.org/software/make/manual/make.html#General-Search 
Ich glaube das ist(nach überfliegen des Textes)
dafür da, wo make nach was bestimmtem suchen soll(in diesem Fall  *.c 
und *.a)

von Janvi (Gast)


Lesenswert?

Würde mir obenstehendes makefile gerne auf eigene Bedürfnisse umbauen.
Grundsätzlich verstehe ich aber den Schleifenmechanismus von make nicht.
Wie es aussieht, sind folgende Zeilen wesentlich beteiligt:
1
#Dies sind die am Projekt beteiligten Quelldateien
2
#das Startup File wird später noch dazugehängt
3
SRCS = delay_taster.c system_stm32f4xx.c
4
5
#Projektname hängt ab von den Quellen (SRCS)
6
$(PROJ_NAME).elf: $(SRCS)
7
8
#das Projekt wird durch (mehrfachen) Aufruf von CC zusammengebaut
9
  $(CC) $(CFLAGS) $^ -o $@ -Llib -lstm32f4

Soweit ich weis, muss CC pro Quelldatei aufgerufen werden und dabei 
immer der jeweilige Name der Quelldatei übergeben werden. Das passiert 
mit
$^ oder $@ (?) und anschliessend muss gelinkt werden. Wo findet der 
Schleifenmechanismus bzw. der wiederholte Aufruf von CC statt und was 
ist das Kriterium für make zur Terminierung der Schleife ? Leider bin 
ich dazu in div. make Beschreibungen auch nicht schlauer geworden.

von Dr. Pinguin (Gast)


Lesenswert?

Janvi schrieb:
> Grundsätzlich verstehe ich aber den Schleifenmechanismus von make nicht.

Welchen Schleifenmechanismus?

> Wie es aussieht, sind folgende Zeilen wesentlich beteiligt:
> SRCS = delay_taster.c system_stm32f4xx.c

Hier wird die rekursive Variable SRCS definiert.

> #Projektname hängt ab von den Quellen (SRCS)
> $(PROJ_NAME).elf: $(SRCS)

Hier wird eine Regel definiert.
Links stehen die Targets, rechts die Voraussetzungen dafür.

> #das Projekt wird durch (mehrfachen) Aufruf von CC zusammengebaut
>   $(CC) $(CFLAGS) $^ -o $@ -Llib -lstm32f4

Hier steht ein Befehl. Die Variablen werden aufgelöst.
Zwei besondere Variable sind $^ und $@, es sind sogenannte automatische 
Variable (gibt sieben davon in make).
$^ steht für alle Dateinamen der Voraussetzungen, wobei Duplikate schon 
entfernt wurden.
$@ steht für den Dateinamen des Targets.

> Soweit ich weis, muss CC pro Quelldatei aufgerufen werden und dabei
> immer der jeweilige Name der Quelldatei übergeben werden. Das passiert
> mit
> $^ oder $@ (?) und anschliessend muss gelinkt werden. Wo findet der
> Schleifenmechanismus bzw. der wiederholte Aufruf von CC statt und was
> ist das Kriterium für make zur Terminierung der Schleife ? Leider bin
> ich dazu in div. make Beschreibungen auch nicht schlauer geworden.

Vereinfacht gesagt, besteht das Makefile aus Regeln. Die werden 
ausgewertet und wenn in einer Regel für eine oder mehrere der 
vorausgesetzten Dateien wiederum Regeln existieren, werden diese zuerst 
ausgewertet. Das Ganze dann rekursiv.
Gibt natürlich noch viele Spezialitäten wie Wildcards, spezielle 
Targets, Funktionen, Macros und vieles mehr. Das sollte aber für Deine 
Zwecke größtenteils uninteressant sein.

von W.S. (Gast)


Lesenswert?

Walter T. schrieb:
> Der langen Frage kurzer Sinn: Kann mir jemand ein lesbares oder
> zumindest funktionierende Makefile für diese Plattform empfehlen?

Nein.

Es ist hier wieder einmal genau so, wie sonst auch immer: Keiner der 
Leute, die auf Makefiles schwören, kann es wirklich.

Stattdessen wird immer wieder irgend ein altes Makefile hergenommen, 
daran herum-modifiziert und ausprobiert bis es irgendwie funktioniert.

Ich für meinen Teil hab da das Kind mit dem Bade ausgeschüttet und auf 
Makefiles komplettiko verzichtet. Es ist für kleinere Projekte viel 
einfacher, sämtliche Compiler- Assembler- und Linker-aufrufe in eine 
poplige Batchdatei zu schreiben und später zwecks Übersetzung einfach 
dort mit dem modernen Faustkeil (Maus) draufzuhauen.

W.S.

von Dr. Pinguin (Gast)


Lesenswert?

W.S. schrieb:
> Walter T. schrieb:
>> Der langen Frage kurzer Sinn: Kann mir jemand ein lesbares oder
>> zumindest funktionierende Makefile für diese Plattform empfehlen?
>
> Nein.
>
> Es ist hier wieder einmal genau so, wie sonst auch immer: Keiner der
> Leute, die auf Makefiles schwören, kann es wirklich.


So ein Quark. Warum schließt Du von Dir auf andere?


> Stattdessen wird immer wieder irgend ein altes Makefile hergenommen,
> daran herum-modifiziert und ausprobiert bis es irgendwie funktioniert.


Ist vielleicht Deine Vorgehensweise.


> Ich für meinen Teil hab da das Kind mit dem Bade ausgeschüttet und auf


Immerhin erkannt...


> Makefiles komplettiko verzichtet. Es ist für kleinere Projekte viel
> einfacher, sämtliche Compiler- Assembler- und Linker-aufrufe in eine
> poplige Batchdatei zu schreiben und später zwecks Übersetzung einfach
> dort mit dem modernen Faustkeil (Maus) draufzuhauen.


Nö, das ist pauschal falsch. Ein Makefile für kleinere Projekte ist 
mindestens ebenso schnell erstellt. Ist ja schließlich keine 
Wissenschaft, und mit Sicherheit einfacher als embedded-Programmierung 
an sich.


@janvi:
Besorg Dir mal ein gutes Tutorial, da sollte schon alles drin stehen, 
was Du für Deine Zwecke brauchst. Das ist nämlich gar nicht so viel.

von Bernd K. (prof7bit)


Lesenswert?

Ich werf noch das hier in die Runde, das ist ein bare minimum makefile 
projekt für STM32F401RE, direkt verwendbar mit dem NUCLEO-F401RE 
Demo-Board von ST.

https://github.com/prof7bit/bare_metal_stm32f401xe

von Clemens L. (c_l)


Lesenswert?

W.S. schrieb:
> Es ist für kleinere Projekte viel einfacher, sämtliche Compiler-
> Assembler- und Linker-aufrufe in eine poplige Batchdatei zu schreiben

Ein Makefile für diese Aufrufe ist genauso einfach:
1
blinky:
2
        compile ...
3
        assemble ...
4
        link ...

Und spätestens, wenn man Targets fürs Flashen/Debuggen/Starten 
hinzufügen will, wird das Makefile einfacher als mehrere Batchdateien.

Für kleine Projekt lohnen sich solche Spezialitäten wie implizite Regeln 
oder hunderte verschachtelte Variablen wirklich nur, wenn man eine 
Vorlage verwendet, die man eh schon verstanden hat.

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

W.S. schrieb:
> sämtliche Compiler- Assembler- und Linker-aufrufe in eine
> poplige Batchdatei zu schreiben und später zwecks Übersetzung einfach
> dort mit dem modernen Faustkeil (Maus) draufzuhauen.

"Wer als Werkzeug nur einen Hammer hat, sieht in jedem Problem einen 
Nagel"

Makefiles sind simpel. Wirklich.
Nicht komplizierter als C-Programme jedenfalls. Im einfachsten Fall 
reichen fünf Zeilen:
1
TARGET=xx
2
3
$(TARGET): xx.o
4
    cc -o xx $<
5
6
%.o:%.c
7
    cc -c $<
Das Target hängt von (ein oder mehreren) Objektfiles ab, die wiederum 
von .c-Dateien abhängen. Wie man aus dem einen das andere macht, steht 
in den Rules.
Alles andere ist nur Farbe und Politur.

von Eric B. (beric)


Lesenswert?

Markus F. schrieb:
> Alles andere ist nur Farbe und Politur.

Bis dann das automatisch erstellen von Dependencies auftaucht. Dann ist 
wieder Zägen, Schrauben und Schleifen angesagt ;-)

: Bearbeitet durch User
von J. V. (janvi)


Lesenswert?

Die Grundregeln von Make erscheinen klar. Allerdings habe ich bislang 
immer für jedes Quellfile eine Regel zum erstellen des dazugehörenden 
Objekts gemacht. (Bislang auch mit anderen Compilern als GCC) Hat den 
Vorteil, daß man z. Bsp. eine einzelnde Datei mit anderen Debug oder 
Optimierungsschaltern übersetzen kann wenn man daran gerade debuggt. 
Nachteil ist, dass jedesmal wenn im Projekt ein neues File dazukommt 
(oder wegfällt bzw. zusammengefasst wird) muß an x Stellen geändert 
werden. Mehrere Stellen im Makefile und im Linkerscript.
Daher würde ich den Ansatz mit Schleife bzw. Rekursion gerne näher 
verstehen und offensichtlich bin ich nicht der einzige der sowas nur 
über probieren rauskriegt.

Es scheint ja, daß man die Files dann so aufbauen kann, daß man die 
Quellfiles eben nur in eine Variable schreibt und irgendwas dafür sorgt 
dass gcc mehr als einmal aufgerufen wird obwohl man nur eine Zeile als 
Aufruf angibt. An der Stelle ist GCC ja auch etwas unübersichtlich da er 
intern mehrere Vorgänge inkl. Link u. U. selbst aufrufen kann. Es könnte 
also genausogut sein, dass CC eine Liste von Datein abarbeitet und dazu 
von make nur einmal aufgerufen wird.

Übrigens habe ich "make" von Helmut Herold (Addison Wesley) als 
Beschreibung mit Beispielen und Erklärungen in deutscher Sprache 
durchgelesen.

$@ ist dort als "aktuelles Ziel" beschrieben und
$^ ist überhaupt nicht erklärt und taucht auch in keinem Beispiel auf

scheint aber für obenstehende Tricksereien unentbehrlich.
Rekursion habe ich im makefile bislang so verstanden, daß im makefile 
includes von weiteren Files sind die wieder auf das eigene Verweisen 
aber offensichtlich gibt es noch andere Mechanismen

: Bearbeitet durch User
von Clemens L. (c_l)


Lesenswert?

J. V. schrieb:
> Allerdings habe ich bislang immer für jedes Quellfile eine Regel zum
> erstellen des dazugehörenden Objekts gemacht. [...]Hat den Vorteil,
> daß man z. Bsp. eine einzelnde Datei mit anderen Debug oder
> Optimierungsschaltern übersetzen kann wenn man daran gerade debuggt.

Das geht auch mit impliziten Regeln:
1
%.o: %.c
2
        $(CC) $(CFLAGS) -c -o $@ $<
3
4
EinzelneDatei.o: CFLAGS = -g -O42

> Rekursion habe ich im makefile bislang so verstanden, daß im makefile
> includes von weiteren Files sind die wieder auf das eigene Verweisen

Mit "=" definierte Variablen sind rekursiv (z.B: X = $(Y)).

Die andere Rekursion (aus "Recursive Make Considered Harmful") betrifft 
Unterverzeichnisse, für die Make rekursiv aufgerufen wird.

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

J. V. schrieb:
> Die Grundregeln von Make erscheinen klar. Allerdings habe ich bislang
> immer für jedes Quellfile eine Regel zum erstellen des dazugehörenden
> Objekts gemacht. (Bislang auch mit anderen Compilern als GCC) Hat den
> Vorteil, daß man z. Bsp. eine einzelnde Datei mit anderen Debug oder
> Optimierungsschaltern übersetzen kann wenn man daran gerade debuggt.

das kann man auch einfacher erreichen, ohne gleich alle Vorteile von 
make herzuschenken. Compiler-Optionen lassen sich in Abhängigkeit vom 
aktuellen Target setzen:
1
CFLAGS = -O3
2
objs/xxx.o: CFLAGS = -g3

definiert beispielsweise, dass CFLAGS auf "-g3" gesetzt wird, wenn das 
aktuelle Target objs/xxx.o heisst. Alle anderen Objektfiles werden mit 
dem Defaultwert von CFLAGS übersetzt, nur dieses eine aber eben mit 
"-g3".

> Nachteil ist, dass jedesmal wenn im Projekt ein neues File dazukommt
> (oder wegfällt bzw. zusammengefasst wird) muß an x Stellen geändert
> werden.

Der Sinn von make ist, genau sowas zu vermeiden. Sonst könntest Du auch 
eine Batch-Datei verwwenden.


> $@ ist dort als "aktuelles Ziel" beschrieben und
> $^ ist überhaupt nicht erklärt und taucht auch in keinem Beispiel auf

$^ ist eine Liste aller Abhängigkeiten des aktuellen Ziels, enthält also 
eine Liste aller Files die benötigt werden, um $@ zu erzeugen.

von W.S. (Gast)


Lesenswert?

Dr. Pinguin schrieb:
> So ein Quark. Warum schließt Du von Dir auf andere?

Ach, noch ein selbsternannter Pinguin-Doktor.

Tja, an den Folgebeiträgen sieht man ziemlich deutlich, daß es offenbar 
doch wesentlich einfacher ist, bei kleineren Projekten auf Zeugs wie 
make schlichtweg zu verzichten und sich mit ner ganz simplen Batchdatei 
zu begnügen.

Aber jeder macht sich seine Probleme aam liebsten halt selbst...

W.S.

von Bernd K. (prof7bit)


Lesenswert?

W.S. schrieb:
> mit ner ganz simplen Batchdatei zu begnügen

Batchdatei wäre mir zu umständlich. Es gibt kein denkbares Szenario beim 
Kompilieren und Linken bei dem ne Batchdatei kleiner, einfacher oder 
leserlicher wäre als ein Makefile gleich einfacher Funktion.

von J. V. (janvi)


Lesenswert?

> $^ ist eine Liste aller Abhängigkeiten

für eine Lister aller Abhängigkeiten steht in anderen Manuals $+
und was ist dann $< schon wieder ?

> Mit "=" definierte Variablen sind rekursiv

Von rekursiven Programmen oder Funktionen bzw. reentrant fähigem Code 
habe ich schon gehört aber von rekursiven Variablen noch nie. (Ist das 
bei einem Interpreter?) Mal ein Versuch zur Erklärung  bzw. wie ich 
jetzt annehme dass die Sache funktionieren könnte:

Variablenname = Inhalt1 Inhalt2 ... Inhaltn

funktioniert logisch so ähnlich wie ein typedef in C, also z. Bsp.
enum Ampel{rot, gelb, grün};

oder vielleicht eher praktisch so ähnlich wie ein struct
struct Ampel{rot, gelb, grün);

Zum Interpretationszeitpunkt des Makefiles richtet make einen Zeiger auf 
das erste Element (im Bsp. rot). Taucht der Variablenname des Ampeltyps 
jetzt in einer Abhängigkeitsbeschreibung auf, so wird die Zeile zur 
Erzeugung des Ziels ausgeführt. Für die Quelldatei wird anstelle von $^ 
der aktuell angezeigte Inhalt der Variablen vom Typ Ampel eingesetzt. 
Danach wird der Zeiger weitergerückt und nachgeschaut ob noch ein 
weiteres Element im Struct folgt. Falls ja, wird der Aufruf zum Erzeugen 
des Ziels wiederholt, falls nein ist die Sache (Zeile) erledigt bzw wird 
nachgeschaut ob es noch eine Folgezeile mit Vorschrift zur Erzeugung des 
Ziels gibt.

Weil beim Aufruf des Compilers nicht nur die Quelldatei sondern auch der 
Name der auszugebenden Objektdatei angegeben werden muß, scheint es 
diese Zeile zu geben:

OBJS = $(SRC:.c=.o)

Für jedes Element von SRC welches mit .c endet, wird das gleiche Element 
in OBJS eingetragen und das Ende .c durch eine Endung .o ersetzt (?) Die 
Bedeutungen von $ oder : in der Zeile sind nicht offensichtlich und 
können entweder nur durch Ausprobieren / Raten oder durch eine Anleitung 
mit Erklärungen und Beispielen verständlich gemacht werden. Es bleibt 
zuletzt noch das Rätsel der Namenswahl von OBJS welches im Makefile nur 
ein einziges Mal vorkommt und $@ trotzdem darauf Bezug nehmen kann. 
(vordefinierter Name?) Jedenfalls überfordern die GNU Erfinder meine 
Inutition hierbei bei weitem wenn sie annmehmen daß dies alles 
selbsterklärend ist.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

J. V. schrieb:
> [Fehlinterpretationen, Falschvermutungen]
>
> Jedenfalls überfordern die GNU Erfinder meine
> Inutition hierbei bei weitem wenn sie annmehmen daß dies alles
> selbsterklärend ist.

Das nehmen sie mitnichten an.

Sie nehmen stattdessen an daß Du das Manual mal grob überfliegst und 
dann bookmarkst (zum jederzeitigen Nachschlagen) und dann mit ein paar 
leicht verständlichen Tutorials anfängst die dich mit vielen einfachen 
Beispielen und Erklärungen behutsam in die Materie einführen.

von Joerg W. (joergwolfram)


Angehängte Dateien:

Lesenswert?

Im Anhang mal ein Makefile, wie ich es aktuell für verschiedene 
Mikrocontroller-Familien nutze. Dabei nutze ich nur eigene Bibliotheken, 
Linkerfiles etc. und habe einen "festen Aufbau":

- src enthält alle Quelltext-Dateien
- inc enthält ale Projekt-spezifischen Includes
- build hier werden die Objektfiles abgelegt

Mittels "make flash" wird ein Hexfile (bei mir: Motorola-Format) für das 
Flash erzeugt und gleich programmiert. Das minimiert das ganze Handling 
und man kann sich mehr auf den Code konzentrieren. Mittels "make run" 
wird das Projekt so gebaut, dass es komplett im RAM läuft und dann 
dorthin übertragen und gestartet. Dafür verwende ich ein getrenntes 
Linkerscript. Und mittels "make lib" wird eine linkbare Bibliothek 
erzeugt, wobei ich vorher noch die main.c umbenenne, damit mir main() 
nicht mit in die Bibliothek rutscht.

Die makefiles für andere Controller-Plattfoermen und den PC sind dabei 
fast identisch, auch wenn manchmal der SDCC zum Einsatz kommt. 
Angefangen habe ich auch mit Compile-Scripten, aber wenn man wegen jeder 
kleinen Änderung das komplette Projekt neu übersetzen muß, wird das auf 
die Dauer nervig.

Jörg

von Markus F. (mfro)


Lesenswert?

J. V. schrieb:
> Jedenfalls überfordern die GNU Erfinder meine
> Inutition hierbei bei weitem wenn sie annmehmen daß dies alles
> selbsterklärend ist.

In Anlehnung an einen Werbespruch:

"Wer hat's erfunden?"

Die GNU's jedenfalls nicht. make ist so alt wie Unix, GNU make ist ein 
Klon davon (mit ein paar Erweiterungen).

Das heisst, dass das schon ein paar mehr Leute als bloß "die irren 
Linux-Jünger" verstanden haben. Falls das ein Anreiz ist, sich mal 
**richtig** reinzudenken.

von J. V. (janvi)


Lesenswert?

> Dr. Pinguin schrieb:
> es sind sogenannte automatische Variable (gibt sieben davon in make)

Die 7 automatische Variablen von (Gnu)Make nach gefühlten 7 Jahren Make 
Studium (Im deutschen Make-Buch von Helmut Herold sind nicht mal alle 7 
erwähnt)

$@  enthält den Dateinamen der Zieldatei der davorstehenden Regel
$%  Dateiname des Archivs wenn Zieldatei der davorstehenden Regel
  in einem Bibliotheksarchiv steht
$<  Dateiname der ersten Abhängigkeit der davorstehenden Regel
  (Zuwas soll das gut sein ? Wenn weitere Abhängigk. Header sind ?)
$?  Dateinamen aller Abhängigkeiten der davorstehenden Regel,
  wenn Datum/Uhrzeit des Dateinamens neuer als die Zieldatei ist.
$*  Dateiname der Zieldatei der davorstehenden Regel ohne Erweiterung
  Nützlich zur Konstruktion von Dateinamen mit anderen Endungen,
  Kann mit % wieder gelesen bzw. woanders eingesetzt werden
$+  (bei nmake $**) enhält alle Abhängigkeiten der davorstehenden Regel
$^  (nicht bei nmake) wie $+ jedoch ohne Duplikate (zu was gut ?)
  Es scheint, dass gcc auch eine Liste von Quell-Dateien akzeptiert

Rekursive Variablen sind mir in Sinn und Funktion weiter nicht plausibel 
und vielleicht trifft dies auch den Kern meiner ersten Frage nach dem 
„Schleifenmechanismus“.

PFAD = /USR/HOME
PFAD = $(PFAD):/data/dir
mag als Variable rekursiv sein, kann aber nicht terminieren weshalb es
PFAD := /data/dir gibt
(oder ist das += ?) Aber es scheint, daß ich weitere 7 Jahre in 
Stallmannschen Original-Files lesen muß da der Thread hier schon 
reichlich verfahren ist. Vielleicht schaut aber doch mal wieder ein 
netter Linuxer vorbei der noch andere Tipps als Manual lesen hat ...

von Joerg W. (joergwolfram)


Angehängte Dateien:

Lesenswert?

Das Konstrukt
1
CSOURCES     := $(shell find ./src -type f -name *.c)
2
COBJECTS     := $(patsubst ./%,build/%,$(CSOURCES:.c=.o))
3
4
ASOURCES     := $(shell find ./src -type f -name *.s)
5
AOBJECTS     := $(patsubst ./%,build/%,$(ASOURCES:.s=.o))

sucht in ./src/ rekursiv nach .c und .s Dateien. Zuerst wird mit find 
nach den Source-Dateien gesucht. (-> CSOURCES). Dann wird src durch 
build ersetzt und .c bzw. .s in .o

Der Aufruf erfolgt eigentlich "von hinten", d.h. die Regel für die 
Source wird von der Regel für die Objektdateien aufgerufen. Da ich oft C 
und ASM mixe, habe ich dafür unterschiedliche Regeln vorgesehen, z.B. 
wenn man einen "externen" Assembler verwendet.

Kompiliert wird mit:
1
bin:  dir $(COBJECTS) $(AOBJECTS)
2
...
3
build/%.o: ./%.c
4
  mkdir -p $(dir $@)
5
  $(CC) $(CFLAGS) -c -o $@ $<
6
7
build/%.o: ./%.s
8
  mkdir -p $(dir $@)
9
  $(CC) $(CFLAGS) -c -o $@ $<
10
11
dir:  
12
  mkdir -p build
13
...

Man braucht halt find dazu, aber das sollte ja eh auf jedem 
Linux-System vorhanden sein. Ich benutze das schon seit ein paar Jahren 
so, genauer erklären kann ich es jetzt auch nicht.

Im Anhang noch ein Makefile, wie ich es auf dem PC benutze. Letztendlich 
ist es von der Struktur her fast identisch.

von Markus F. (mfro)


Lesenswert?

Joerg W. schrieb:
> Das Konstrukt
>
1
CSOURCES     := $(shell find ./src -type f -name *.c)

Hab' ich so ähnlich eine Weile auch mal benutzt, es dann aber (wegen 
schlechter Erfahrungen) wieder gelassen. Sicherheit vor Bequemlichkeit.

Es hat den Nachteil, dass man (insbesondere bei komplexen und/oder 
grossen Projekten) u.U. nicht merkt, wenn eine Quelldatei im Source-Tree 
verloren geht oder (möglicherweise schlimmer) sich eine "einschmuggelt" 
die da nichts verloren hat.

Mit der Suche nach so einem Fehler kann man u.U. Stunden verbringen.

Mir ist es lieber, wenn das Makefile "weiss", was zum Projekt gehört und 
was nicht (also eine explizite "SRCS-Variable" oder ähnliches hat). Dann 
kann man auch mal eine Quelle, die eigentlich nur dazu gedacht ist, 
irgendwas auszuprobieren, im Sourceverzeichnis liegen lassen, ohne dass 
gleich Schlimmeres passiert.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Markus F. schrieb:
> Das heisst, dass das schon ein paar mehr Leute als bloß "die irren
> Linux-Jünger" verstanden haben. Falls das ein Anreiz ist, sich mal
> **richtig** reinzudenken.

Es gibt schier unendlich vieles, was mal aktueller Stand ser Technik war 
und inzwischen obsolet ist. z.B. Feuersteinklingen und Faustkeil.

Das Prinzip ist ubiquitär. Denk mal zum Beispiel an tar. Inzwischen gibt 
es keine Lochbänder mehr, aber "die irren Linux-Jünger" benutzen das 
immer noch, bloß weil sie nicht im Geringsten verstanden haben, wozu die 
Neuerung beim zip Format denn gut sein sollen.

Auf dem Lochband konnte man von Hand anhand der 256 Byte langen nul 
Vorläufe und der oktal gestanzten Header erkennen, wo im Archiv eine 
Datei denn losgeht und sogar, wie sie heißt und wie lang sie ist. Wer 
kann das bei einem tar auf dem Stick? oder gar bei einem tgz irgendwo?

Aber die Funktionalität bei zip, daß man tatsächlich auf alle einzelnen 
Files im Archiv separat zugreifen kann, ohne alles zuvor auszupacken, 
haben diese ewig Gestrigen nicht kapiert.

Genau so geht es mit den Makefiles. Sind Schnee von gestern, ach was sag 
ich, von vorgestern. Der ursprüngliche Sinn ist perdue, der bestand 
nämlich aus dem datumsabhängigen Kompilieren nur der Dateien, die es 
nötig hatten - weil damals die Rechner eben dramatisch langsamer waren.

Ob nun heutzutage ein PC bei deinem µC-Programm 1 Sekunde oder nur 100 
ms zum kompletten Übersetzen von allen Quellen braucht, ist völlig egal. 
Stattdessen erwarten die Make-Jünger, daß man sich in die durchaus nicht 
triviale Syntax von Make einarbeitet - aus meiner Sicht so überflüssig 
wie ein Kropf.

Jaja, richtig gute Programmiersprachen haben sowas ins Grundkonzept 
eingebaut, wie (allen voran) Pascal mit seiner Teilung von Interface ud 
Implementation. Aber das nur zu Anheizen der Stimmung...

W.S.

von eagle user (Gast)


Lesenswert?

W.S. schrieb:

> Genau so geht es mit den Makefiles. Sind Schnee von gestern, ach was sag
> ich, von vorgestern. Der ursprüngliche Sinn ist perdue, der bestand
> nämlich aus dem datumsabhängigen Kompilieren nur der Dateien, die es
> nötig hatten - weil damals die Rechner eben dramatisch langsamer waren.

Warte nur, bis alle Atomkraftwerke abgeschaltet sind, der Strom 
rationiert wird und der PC mit 3 Watt auskommen muss!

Obwohl, dann bekommt "Batch File" vielleicht wieder seine ursprüngliche 
Bedeutung - wenn Leute ohne Kühlschrank Rechenleistung verkaufen...

;)

P.S.: Makefiles für bestimmte Chips sind noch kranker als Batch Files.

von Bernd K. (prof7bit)


Lesenswert?

W.S. schrieb:
> Aber das nur zu Anheizen der Stimmung...

Warum? Langeweile? Zuwenig Getrolle hier so daß man nachhelfen muss?

von Markus F. (mfro)


Lesenswert?

W.S. schrieb:
> Markus F. schrieb:
>> Das heisst, dass das schon ein paar mehr Leute als bloß "die irren
>> Linux-Jünger" verstanden haben. Falls das ein Anreiz ist, sich mal
>> **richtig** reinzudenken.
>
> Es gibt schier unendlich vieles, was mal aktueller Stand ser Technik war
> und inzwischen obsolet ist. z.B. Feuersteinklingen und Faustkeil.
>
> Das Prinzip ist ubiquitär.

Super Wort. Musste ich googeln, aber werde ich mir merken.

> Denk mal zum Beispiel an tar. Inzwischen gibt
> es keine Lochbänder mehr, aber "die irren Linux-Jünger" benutzen das
> immer noch, bloß weil sie nicht im Geringsten verstanden haben, wozu die
> Neuerung beim zip Format denn gut sein sollen.
>
> Auf dem Lochband konnte man von Hand anhand der 256 Byte langen nul
> Vorläufe und der oktal gestanzten Header erkennen, wo im Archiv eine
> Datei denn losgeht und sogar, wie sie heißt und wie lang sie ist. Wer
> kann das bei einem tar auf dem Stick? oder gar bei einem tgz irgendwo?
>
> Aber die Funktionalität bei zip, daß man tatsächlich auf alle einzelnen
> Files im Archiv separat zugreifen kann, ohne alles zuvor auszupacken,
> haben diese ewig Gestrigen nicht kapiert.
>

Erfreulicherweise gibt's für jeden Zweck passende Werkzeuge und ihr 
vernünftiger Einsatz ist nur durch die Intelligenz des Anwenders 
beschränkt.

Zip ist prima, um (einige wenige) Dateien zu komprimieren. Versuch' mal 
ein 10TB Magnetband mit zip zu füllen. Da werden deine Millisekunden 
plötzlich reichlich lang. Wenn Du's dann doch geschafft hast und nach 
fünf Jahren das vorletzte Bit gekippt ist, kannst Du mit zip kein 
einziges Byte des Bandes mehr lesen. Tar kann das.

Wer als Werkzeug nur einen Hammer hat, sieht in jedem Problem einen 
Nagel.

> Genau so geht es mit den Makefiles. Sind Schnee von gestern, ach was sag
> ich, von vorgestern. Der ursprüngliche Sinn ist perdue, der bestand
> nämlich aus dem datumsabhängigen Kompilieren nur der Dateien, die es
> nötig hatten - weil damals die Rechner eben dramatisch langsamer waren.
>
> Ob nun heutzutage ein PC bei deinem µC-Programm 1 Sekunde oder nur 100
> ms zum kompletten Übersetzen von allen Quellen braucht, ist völlig egal.
> Stattdessen erwarten die Make-Jünger, daß man sich in die durchaus nicht
> triviale Syntax von Make einarbeitet - aus meiner Sicht so überflüssig
> wie ein Kropf.
>

Selbe Geschichte. Trivialprogramme, die nur aus drei Quellfiles 
bestehen, lassen sich natürlich ohne grosse Einschränkungen "einfach so" 
zusammenklopfen, ohne Hirnschmalz in ein Makefile zu stecken.

Meine Programme sind üblicherweise ein wenig komplexer, als dass sie 
schon nach einer Sekunde übersetzt wären und ich bin ehrlich gesagt 
nicht gewillt, meine kostbare Lebenszeit damit zu vergeuden, auf ein 
dumbes Batchfile zu warten, das Dinge tut, die gar nicht notwendig sind.

Wem's schon zu viel ist, ein bisschen Denkleistung in ein Makefile zu 
stecken und damit den Build-Prozess intelligent und stabil zu gestalten, 
weil Computer ja heute ach so schnell sind und alles viel besser können, 
dessen Code möchte ich gar nicht erst sehen.

Wer als Werkzeug nur einen Hammer ...

Schönen Sonntag!

von Walter T. (nicolas)


Lesenswert?

Ein Makefile, das nur unter Linux funktioniert, finde ich für ein 
µC-Programm nicht sinnvoll. (Für Linux-Installationspakete sieht das 
natürlich anders aus.)

Für mich hat ein Makefile (u.A.) gerade den Zweck, nicht mehr auf eine 
bestimmte build-Umgebung angewiesen zu sein, sondern Projekte 
plattformübergreifend erzeugen zu können.

von Bernd K. (prof7bit)


Lesenswert?

Walter T. schrieb:
> Ein Makefile, das nur unter Linux funktioniert, finde ich für ein
> µC-Programm nicht sinnvoll.

Make und die anderen GNU Tools gibts ja zum Glück auch für Windows, man 
muss schon ganz schönen Mist bauen um versehentlich ein Makefile zu 
produzieren das unter Linux funktioniert aber nicht unter Cygwin.

von J. V. (janvi)


Lesenswert?

>man muss schon ganz schönen Mist bauen um versehentlich ein Makefile zu
>produzieren das unter Linux funktioniert aber nicht unter Cygwin.

So arg braucht man keinen Mist zu bauen sondern nur in der Community 
anhören daß man eben die Manuals lesen soll anstelle faul zufragen. Bei 
freier Software haben Andere schon den Mist für einen gebaut und man 
braucht sich nur wundern warum man zu blöde dazu ist und nix geht:

https://bugs.launchpad.net/gcc-arm-embedded/+bug/1282943

Wie gut, daß man da alle 1282843 known bugs nachlesen kann und im 
Gegensatz zu kommerziellen Compilern mit vielleicht funktionierenden 
IDEs kostet das dann auch nix extra. Da schadet es dann zumindest nichts 
wenn man beim Anschauen sofort sieht ob eine automatische Variable jetzt 
rekursiv ist oder nicht. Die GNU kompatible Teilmenge der automatischen 
Variablen sind im Buch von Helmut Herold übrigens als "interne Makros" 
beschrieben wo man als Neuling auch jederzeit alleine draufkommen kann 
um dann gleich zu wissen ob und was man selbst falsch gemacht hat.

Jedenfalls lächeln verschiedene Leute um mich rum immer nur wenn ich mal 
wieder erzähle, daß man seine Quellen nicht in "Eigene Dateien" ablegen 
soll, weil das dazugehörenden Programme den Pfad wegen dem Leerzeichen 
sonst nicht mehr findet. Und das mit den Umlauten in Dateinamen ist 
genauso aktuell und kaum von vorgestern.

: Bearbeitet durch User
von W.S. (Gast)


Lesenswert?

Walter T. schrieb:
> Für mich hat ein Makefile (u.A.) gerade den Zweck, nicht mehr auf eine
> bestimmte build-Umgebung angewiesen zu sein, sondern Projekte
> plattformübergreifend erzeugen zu können.

Ach Walter, du wirst immer an irgend einer Stelle eingreifen müssen - 
und sei es nur, um die nötigen Pfadvorgaben auf einer anderen Maschine 
oder einem anderen Toolset anzupassen.

Insofern ist diese ganze Diskussion unsinnig. Diejenigen, die selbst für 
ein 10 Quellen Projekt ein Makefile aufsetzen (oder zumindest dies hier 
behaupten), wird man mit Vernunft nicht umstimmen können und diejenigen, 
denen das zu blöd ist, greifen zu irgend einer IDE, in der Hofnung, daß 
die es ihnen besorgt. Und beide Sorten glauben den Verstand mit 
Schöpfkellen gelöffelt zu haben.

Ach, was soll's.

W.S.

von Markus F. (mfro)


Lesenswert?

W.S. schrieb:
> Ach, was soll's.

Genau. Was soll's.

Für mich gehört zu ernsthafter Softwareentwicklung nicht nur das 
Verständnis der Programmiersprache und der Algorithmen, sondern genauso 
auch das für die Tools (das betrifft nicht nur make, sondern auch die 
Toolchain und das (ein) VCS). Nur in der (richtigen) Kombination der 
Tools und der richtigen Anwendung ist vernünftige Reproduzierbarkeit 
(=Qualität) zu gewährleisten.

Ob das Build-Tool nun make oder CMake oder noch was anderes ist, ist 
eigentlich wurscht, aber der Standard ist nun mal make.

Und um auch noch was Konstruktiv(er)es beizutragen: meine Makefiles 
enthalten meist folgendes Target, das manchmal ganz hilfreich ist, wenn 
man nicht mehr durchblickt:
1
.PHONY: printvars
2
printvars:
3
    @$(foreach v,$(.VARIABLES), $(if $(filter-out environment% default automatic, $(origin $v)),$(warning $v=$($v))))

Dann einfach mal gucken, was bei "make printvars" erscheint.

von J. V. (janvi)


Lesenswert?

Habe bei Jörg Wolfram jetzt kräfig abgeschrieben und es funktioniert.
Leider weis ich nicht warum.

Die Abhängigkeit für den Compiler %,o: %.c hatte ich zunächst
1
$(OBJS): $(CSOURCES)
Damit wird gcc nur einmal mit einer Liste von Quelldateien aufgerufen,
was wohl grundsätzlich geht mir aber unübersichtlich erscheint und im 
konkreten Fall zudem zu Fehlern führt. (fatal error: cannot specify -o 
with -c with multiple files)

Mit %.o: %.c wird gcc pro Quelle je einmal aufgerufen. Das ist gut aber 
ich weis nicht warum. Ist das eine (implizite?) Pattern-Regel? 
Eigentlich müssten dafür ja die Variablen $@ und $^ zuständig sein und 
die werden zwischen funktionierender und nicht funktionierender Version 
nicht mal verändert. Ein Tausch von $^ in $? bringt scheinbar auch keine 
Änderung.
1
COPTS = -Wall -Os -funsigned-char -xc -mlittle-endian -mthumb -mno-thumb-interwork
2
COPTS += -c -mcpu=cortex-m3 -mno-tpcs-frame -gdwarf-2 --function-sections
3
SOPTS = -mcpu=cortex-m3 -gdwarf-2 -mthumb
4
LOPTS := -T linkfile.ld -Map=file.map --cref -gc-sections -o out.axf
5
6
cpuinit.o:  COPTS += -O1 -save-temps
7
8
SSOURCES := startup_stm32f10x_ld.s
9
CSOURCES := cpuinit.c main.c flop.c misc.c 
10
CSOURCES += stm32f10x_adc.c stm32f10x_dma.c stm32f10x_flash.c stm32f10x_gpio.c 
11
CSOURCES += stm32f10x_rcc.c stm32f10x_tim.c stm32f10x_it.c
12
13
OBJS  = $(CSOURCES:.c=.o)
14
OBJS += $(SSOURCES:.s=.o)
15
16
out.axf: $(OBJS)
17
  arm-none-eabi-ld $(LOPTS) $(OBJS)
18
  arm-none-eabi-objcopy -O ihex out.axf out.hex
19
  arm-none-eabi-objcopy -O binary out.axf out.bin
20
21
%.o: %.c
22
  arm-none-eabi-gcc $(COPTS) -c $? -o $@
23
24
%.o: %.s
25
  arm-none-eabi-as $(SOPTS) -o $@ $?
26
27
clean:
28
  rm *.o
29
  rm out.*

: Bearbeitet durch User
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.