Hallo, ich weiss nicht ob das so richtig hier her passt, aber ich finde keinen besseren Platz. Kurz zu dem/die Projekten. Ich brauche da ein paar Tipps wie man das mit Make lösen kann. Es handelt sich um ein Projekt das bisher aus 3 ATmegas, mit unterschiedlichem Takt, besteht. Kurz zur groben bisherigen File Struktur source/global_files/ source/tx_main/bootloader source/tx_main/main source/tx_main/lcd source/rx_main/bootloader source/rx_main/main source/pc/ unter global Files liegen bisher Include Files die in allen anderen referenziert werden mit defines, structs etc. Hier sollen nun auch "c" Files hin mit Routinen die überall gleich sind. Da zum Teil die ATmegas unterschiedlich sind und die Taktfrequenz, fällt eine lib weg. Nun dachte ich, ich kann die "c" File im make das z.B. in "source/tx_main/main" liegt relativ einbinden in der Art: "../../global_files" so wie bei den Includes. Das geht leider nicht. Hier kommt eine Fehlermeldung das das Object File nicht erzeugt werden konnte, da dass object Directory fehlt (müsste ich genau nochmal ausprobieren wenn notwendig). Wie löst man so etwas ? Das wird doch bestimmt in vielen Projekten benötigt. Rekursive makes ? Wie gebe ich dann Parameter wie CPU und FCPU weiter ? Wäre es dann ein make das alle "Projekt Teile" auf einmal erstellt ? Falls wichtig, ich entwickle unter Linux und das Projekt liegt unter SVN Kontrolle. Von "Soft" links würde ich gerne Abstand nehmen. Für Tipps bin ich dankbar Juergen
In meinen — allerdings nur privaten — Projekten habe ich mir dazu ein kleines Quell-Repository angelegt, weil wie gesagt Libs ausscheiden wegen mangelnder Skalierbarkeit (SFRs, Defines, F_CPU, Port-Definitionen im Projekt, etc). Im Makefile gebe ich dann die Quellen an, die aus dem Repository stammen:
1 | COMMON = ../common |
2 | COMMON_SRC = uart-simple.c uart.h soft-reset.h ... |
3 | SRC = main.c uart-simple.c uartio.c ... |
und im projektunabhängigen Makefileschnippel dann
1 | .PHONY: clean |
2 | .PHONY: copies copyclean dependclean realclean |
3 | |
4 | .PRECIOUS: $(COMMON_SRC) |
5 | |
6 | copies: $(COMMON_SRC) |
7 | |
8 | copyclean: |
9 | rm -f $(wildcard $(COMMON_SRC)) |
10 | |
11 | realclean: dependclean copyclean clean |
12 | |
13 | $(COMMON_SRC): % : $(COMMON)/% |
14 | cp $< $@ |
15 | |
16 | dependclean: |
17 | rm -f .depend |
18 | |
19 | .depend: $(COMMON_SRC) $(EXTRA_DEPEND) $(SRC) |
20 | $(CC) $(CCLANG) -MM $(SRC) -mmcu=$(MCU_TARGET) $(DEFS) $(INCLUDES) \ |
21 | | sed -e 's/\.o\:/.s:/' \ |
22 | > .depend |
23 | |
24 | -include .depend |
SRC sind die "normalen" Quellen, die Compiliert/Assembliert werden und COMMON_SRC die sachen aus dem Repository. D.h. die Quellen aus dem Repository werden einmal ins Projektverzeichnis kopiert und bleiben dann dort und können dann dort auch überschrieben werden (bei lokalen Änderungen ist es sinnvoll sie aus COMMON_SRC zu entfernen). Ansonsten wird bei einer Änderung im Repository die Arbeitskopie überschrieben. Anstatt zu kopieren, kann man natürlich auch aus SVN oder git auschecken; für meine Bastlprojekte führe ich kein VCS. Dieser Ansatz ist dann praktikabel, wenn die Quellen im Quell-Repository hinreichend stabil und allgemein genug sind, um nicht doch für jedes Projekt wieder Anpassungen machenzu müssen. Dazu gehören zB UART-Implementierungen, die zwar noch vom aktuellen µC anhängen per -mmcu oder avr/io.h, aber sonst keine Änderungen mehr benötigen ausser zB per Makro ob man eine Poll-Version mächte oder eine gepufferte, Interrupt-getriebene Verson. Anderer typischer Use-Case sind Makros für die Port-Zugriffe wie SET(PORT_LED), MAKE_IN(PORT_LED), MAKE_OUT(PORT_LED), TOGGLE(PORT_LED), etc. Daneben gibt es bestimmt auch viele andere, professionellere Ansätze ;-) Aber für meine Projekte tut's das schon seit langem und es ist einfach, ein neues Projekt zusammenzustöpseln.
Jürgen Sachs schrieb: > Wie löst man so etwas ? Das wird doch bestimmt in vielen Projekten > benötigt. > Rekursive makes ? Ob Du es rekursives Make nennst oder nicht, aber das Aufteilen in je ein Makefile für jedes zu erzeugende Programm ist sicher sinnvoll. Die einzelnen Makes werden dann kleiner und übersichtlicher. Ein übergeordnetes Makefile ruft dann diese 3 makes auf. Du musst eben auch beachten, dass die komplierten Objects für die gemeinsam benutzten Quellen in separate Verzeichnisse müssen, weil sie für unterschiedliche Prozessoren kompiliert werden müssen. Ich würde zusätzliche Verzeichnisse anlegen implement/tx_main implement/rx_main implement/pc und in diesen macht je ein makefile aus den relativ referenzierbaren Quellen das jeweilige Programm. Damit die Quellen gefunden werden musst Du entweder eine eigen Regel schreiben, z.B. %.o : ../source/global_files/%.c $(CC) ... mit der man aus .c files in ../source/global_files ein gleichnamiges obj im aktuellen Verzeichnis erzeugst, oder du arbeitest mit VPATH, damit kann man auch den Ort von Quellen angeben. > Wie gebe ich dann Parameter wie CPU und FCPU weiter ? Über die Parameter für das make make CPU=$(CPU) FCPU=$(FCPU) > Wäre es dann ein make das alle "Projekt Teile" auf einmal erstellt ? Ja, siehe oben
Hi, Jürgen, > Es handelt sich um ein Projekt das bisher aus 3 ATmegas, mit > unterschiedlichem Takt, besteht. Verstanden. Aber wo habe ich überlesen, wie die Konfiguration nun aussehen soll? Vielleicht ein Atmega, der die drei bisherigen Programme enthält, der in jede der bisherigen drei Fassungen gesetzt werden kann und dann anhand eines Merkmals erkennt, wo er sitzt und welches Programm abzuarbeiten hat? Oder soll das beim Kompilieren geschehen? Ansonsten - ich habe mit GCC schon .c-Dateien aus anderen Directories eingebunden. Aber die main.c, bzw. die mit dem Namen des Programms, befand sich dabei immer in dem Directory, in dem ich dann auch kompiliert habe. Ciao Wolfgang Horn
jeder Teil - tx_main -rx_main -tx_lcd benutzt einen eigenen Prozessor, der vom Typ her aber fest steht. also tx_main hat einen bootloader und den "main" part der auf einem atmega32 mit 16MHz läuft. Analog für die rx_main (m32@16MHz) und tx_lcd (m16@8MHz). Diese benutzen teile aus global Files (I2C, Uart, Umwandelung Routinen) Es ist auch ausreichend immer nur ein Projekt zu erstellen Gruss Juergen
Danke, Jsachs, jetzt sehe ich klar. Aber ich bekenne auch - den prozessorspezifischen Bootloader habe ich immer getrennt von der Application entwickelt. Defines und Teile der Sourcen waren identisch. Die Fertigung hat dann mit Boundary Scan beides geflasht. Ciao Wolfgang Horn
Jürgen Sachs schrieb: > Hier kommt eine Fehlermeldung das das Object File nicht erzeugt werden > konnte, da dass object Directory fehlt (müsste ich genau nochmal > ausprobieren wenn notwendig). Genaue Fehlermeldung wäre sicherlich hilfreich. Auf jeden Fall sollte sowas mit expliziten Regeln zum Compilieren gehen, weil man dabei die Quell- und Ausgabedatei separat festlegen kann:
1 | COMMON_SRC = ../../common |
2 | |
3 | ... |
4 | |
5 | foo.o: $(COMMON_SRC)/foo.c |
6 | $(CC) $(CFLAGS) -c -o foo.o $(COMMON_SRC)/foo.c |
Mit Suffixregeln gibt es keinen generischen Ansatz, wobei GNU make, wie ich den üblichen "creeping featurism" kenne, dafür sicher irgend- einen Hack, ähm, Hook bietet. ;)
Jörg Wunsch schrieb: > Jürgen Sachs schrieb: >> Hier kommt eine Fehlermeldung das das Object File nicht erzeugt werden >> konnte, da dass object Directory fehlt (müsste ich genau nochmal >> ausprobieren wenn notwendig). > > Genaue Fehlermeldung wäre sicherlich hilfreich.
1 | Compiling C: ../../global_files/uart.c |
2 | avr-gcc -c -mmcu=atmega32 -I. -gdwarf-2 -DF_CPU=16000000UL -O0 -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -Wa,-adhlns=obj/../../global_files/uart.lst -std=gnu99 -Wundef -MD -MP -MF .dep/uart.o.d ../../global_files/uart.c -o obj/../../global_files/uart.o |
3 | Assembler messages: |
4 | Fatal error: can't create obj/../../global_files/uart.o: No such file or directory |
5 | make: *** [obj/../../global_files/uart.o] Fehler 1 |
Warum der Fehler kommt ist mir klar, weil als Ursprung das "obj" genommen wird und nicht "." > Auf jeden Fall sollte sowas mit expliziten Regeln zum Compilieren > gehen, weil man dabei die Quell- und Ausgabedatei separat festlegen > kann: > >
1 | > COMMON_SRC = ../../common |
2 | > |
3 | > ... |
4 | > |
5 | > foo.o: $(COMMON_SRC)/foo.c |
6 | > $(CC) $(CFLAGS) -c -o foo.o $(COMMON_SRC)/foo.c |
7 | > |
> > Mit Suffixregeln gibt es keinen generischen Ansatz, wobei GNU make, > wie ich den üblichen "creeping featurism" kenne, dafür sicher irgend- > einen Hack, ähm, Hook bietet. ;) Verstehe ich das richtig, das ich das nicht mit %o: $COMMON_SRC .... Also eine Regel für alle Files machen kann... Dann muss ich mir make nochmals genau ansehen. Und mach das durch "Rekursive". Ich hab nur noch kein HowTo für make gefunden, das ich verstehe :-( Gibt es kein "Auto make" das nur die "c" files bekommt und den rest Automatisch festlegt ? Gruss Juergen
Jürgen Sachs schrieb: > Verstehe ich das richtig, das ich das nicht mit > %o: $COMMON_SRC .... > Also eine Regel für alle Files machen kann... Jein. Solche Regeln nennt man static pattern rules. Du brauchst aber 2 Regeln, weil Du 2 "Arten" von obj-files hast: die von common und die vom Projekt. OBJ_COMMON := c1.o c2.o OBJ_PROJECT := p1.o p2.o #rule 1, gilt für c-files aus common $(OBJ_COMMON) : %.o : $(COMMON_SRC)/%.c $(CC) ..... #rule 2, gilt für c-files aus lokalem directory $(OBJ_PROJECT) : %.o : %.c #rule 2, $(CC) ..... Jürgen Sachs schrieb: > Gibt es kein "Auto make" das nur die "c" files bekommt und den rest > Automatisch festlegt ? Weiss nicht. Wäre zu einfach und wo bleibt dann der Spass :-)
danke, Teste ich am Wochenende. juergen
automake gibt es natürlich, und möglicherweise könnte es das auch können, was du da willst — aber ob du dich darin erst einarbeiten magst, wage ich zu bezweifeln. ;-)
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.