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
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.
Hallo Lukas, das sieht auf den ersten Blick schon recht gut aus. Aber welchen Zweck erfüllt das python-Script?
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
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.
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
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?
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)
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.
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.
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.
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.
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
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
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.
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
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
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
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.
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.
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.
> $^ 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
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.
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
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.
> 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 ...
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.
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
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.
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.
W.S. schrieb: > Aber das nur zu Anheizen der Stimmung... Warum? Langeweile? Zuwenig Getrolle hier so daß man nachhelfen muss?
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!
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.
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.
>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
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.