Forum: Compiler & IDEs Projekt mit Unterordnern und rekursive Makefiles


von Max M. (maxmicr)


Lesenswert?

Ich stehe gerade vor einem mir großteils unbekannten Projekt, in dem ca. 
20 .c-Dateien in einem src-Ordner liegen (d.h. es gibt keine Unterordner 
für eine übersichtlichere Struktur). Die Makefiles sind aktuell auch auf 
diese Struktur hin ausgelegt.

Ich würde gerne die Möglichkeit schaffen, jede logische Komponente in 
einen Unterordner zu legen und zwar so, dass das Projekt (schlussendlich 
wird eine .hex-Datei erzeugt) kompiliert werden kann.

Aktuell sieht es so aus:

src/main/c/
-----------file_1.c
-----------file_2.c
-----------...
-----------file_n.c

So hätte ich es gerne

src/main/c/
----------Komponente_1/
----------------------file_1.c
----------------------file_2.c
----------------------file_1.h
----------------------file_2.h
----------Komponente_2/
----------------------...
----------...
----------Komponente_n

Ich hab mich nun etwas in Make eingelesen (hab davon ehrlich gesagt 
nicht viel Ahnung) und habe herausgefunden, dass es im Prinzip zwei 
Lösungswegen gibt:

1. Ein Makefile im Ordner src (bzw. src/main/c), dass sich alle 
.c-Dateien zusammensucht und dann das .hex-File erstellt

2. Ein Makefile im Ordner src (bzw. src/main/c) und für jeden 
Unterordner mit Source-Dateien (Komponente_1 etc.) ein extra Makefile, 
dass die enthaltenen .c-Dateien zu .o-Dateien macht. Das 
"Haupt"-Makefile im src-Ordner erzeugt dann aus den .o-Dateien der 
Unterordner das .hex-File (rekursiv).

Mein Problem ist nur, dass ich dazu keine einsteigerfreundliche 
Anleitung finde.
Eine zusätzliche Hürde ist, dass die verschiedenen Header-Dateien auch 
andere Header-Dateien inkludieren und ich nicht weiß, wie und ob man 
diese Abhängigkeiten untereinander überhaupt bewältigen kann?

Für erste Tipps wäre ich sehr, sehr dankbar.

Grüße

P.S. Das Ganze wird mit dem avr-gcc kompiliert, weiß nicht ob diese Info 
nützlich ist.

: Bearbeitet durch User
von Eric B. (beric)


Lesenswert?

http://aegis.sourceforge.net/auug97.pdf

Dieses PDF ist zwar auf englisch und über 20 Jahre alt, aber hat m.M.n 
einen sehr guten Ansatz wie man größere Projekte mit make handeln kann.

Grundsätzlich:
- ein zentrales Makefile mit allem was man zum kompilieren braucht, 
ausser die Liste an Source-Dateien

- in jedem Unterverzeichnis ein "node.mk" o.Ä. was im zentralen Makefile 
eingebunden wird und nur die Source-Dateien im jeweiligen Verzeichnis 
auflistet.

von Oliver S. (oliverso)


Lesenswert?

Bei so wenigen Dateien reicht ein makefile, die Aufteilung auf mehrere 
ist da eher eine akademische Übung.

Und ganz generell wäre eine IDE, die automatisch makefiles erstellt, die 
bequemste Lösung.

Oliver

: Bearbeitet durch User
von Oliver R. (Gast)


Lesenswert?

Ich habe für meine eigenen Projekte eine Art Framework entwickelt, das 
so ähnlich funktioniert. Vielleicht ist es ja für deine Anwendung 
brauchbar bzw. ohne grösseren Aufwand anzupassen:

https://github.com/sourcebox/cpmk

Es arbeitet nicht generell mit rekursiven Makefiles, sondern inkludiert 
optional pro Komponente zwei Makefiles. Damit kann man z.B. 
Compilerflags pro Komponente setzen.

von Markus F. (mfro)


Lesenswert?

Max M. schrieb:
> und habe herausgefunden, dass es im Prinzip zwei
> Lösungswegen gibt

... da gibt es noch einen dritten, sehr einfachen Lösungsweg, der 
manchmal prima ist (für relativ simple, überschaubare Projekte) und 
manchmal überfordert: das einfache Setzen der VPATH-Variable kann u.U. 
deine Wünsche schon erfüllen.

von Max M. (maxmicr)


Lesenswert?

Oliver S. schrieb:
> Und ganz generell wäre eine IDE, die automatisch makefiles erstellt, die
> bequemste Lösung.

Ist mir auch gerade aufgefallen als ich versucht habe, die 
Projektstruktur an meinem privaten PC nachzubauen.
Ich werd morgen mal versuchen, das Projekt mit Atmel Studio und dem 
auto-generierten Makefile zu kompilieren.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

Von IDE generierten Dateien halte ich wenig bis nichts. Man findet sich 
an eine IDE. Ich würde entweder zu selbst geklöppelten makefiles + vom 
GCC erzeugten Dependencydateien (hoher Lerneffekt) oder aber cmake als 
make/Ninja Generator raten.

Matthias

von Oliver S. (oliverso)


Lesenswert?

Μαtthias W. schrieb:
> Von IDE generierten Dateien halte ich wenig bis nichts.
Macht ja nix. Jeder Jeck is anders.

Man findet sich
> Ich würde entweder zu selbst geklöppelten makefiles + vom
> GCC erzeugten Dependencydateien (hoher Lerneffekt)

Programmierst du schon, oder klöppelst du noch?

Oliver

: Bearbeitet durch User
von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> Μαtthias W. schrieb:
>> Von IDE generierten Dateien halte ich wenig bis nichts.
> Macht ja nix. Jeder Jeck is anders.

Foren sind doch dazu da Meinungen auszutauschen oder?

> Man findet sich
>> Ich würde entweder zu selbst geklöppelten makefiles + vom
>> GCC erzeugten Dependencydateien (hoher Lerneffekt)
>
> Programmierst du schon, oder klöppelst du noch?

Ich hab mal lang an einem recht komplexe Konstrukt aus makefiles 
gebastelt. Dafür war dann das Anlegen eines neuen Projekts nur noch das 
anlegen eines Verzeichnis. Damit könnte dann für verschiedene 
Architekturen (x86, x64, Cortex-M, ARM9, Cortex-A) und Betriebssysteme 
(Baremetal, Windows, Linux, Free-RTOS) gebaut werden mit nur einem 
Befehl. Inkl. Unittests, Codecoverage usw. Wüßte nicht wie man das in 
einer einzigen IDE abbilden sollte. Allerdings würde ich dafür auch 
bezahlt :-)

von Vincent H. (vinci)


Lesenswert?

Ein makefile pro Ordner wäre für mich als Liebhaber von Hierarchien der 
absolute Horror. Ich seh da auch keinen Vorteil weil man sich ja via 
shell find eh alle Sourcen aus den Unterordner saugen kann?
1
SRC_DIRS += ./driver/newlib
2
SRC_DIRS += ./src/target
3
# usw. usf.
4
5
SRCS := $(shell find $(SRC_DIRS) -name *asm -or -name *.s -or -name *.S -or -name *.c -or -name *.cc -or -name *.cpp)

Headerabhängigkeiten können durch die vom Compiler generierten .d files 
aufgelöst werden:
1
# Include all dependency files (.d)
2
DEPS := $(OBJS:.o=.d)
3
4
# Create include directories from dependency files
5
INC_DIRS += $(shell find $(SRC_DIRS) -type d)

: Bearbeitet durch User
von DPA (Gast)


Lesenswert?

Vincent H. schrieb:
> Ein makefile pro Ordner wäre für mich als Liebhaber von Hierarchien der
> absolute Horror. Ich seh da auch keinen Vorteil weil man sich ja via
> shell find eh alle Sourcen aus den Unterordner saugen kann?

Es gibt viele verschiedene Gründe und Strategien, die mehrere Makefiles 
rechtfertigen.

Ich mache das manchmal, wenn ich verschiedene Teile ganz anders bauen 
muss. z.B. bei diesem Monster hier, mit dem ich devuan images fürs 
librem5 baue:
https://github.com/Daniel-Abrecht/librem5-image-builder

Da hab ich erstmal eine Datei die ich in allen Makefiles einbinde, und 
allgemeines wie z.B. git repos clonen, resetten und aktualisieren, repo 
urls und andere Einstellungen ändern, etc. enthält:
 https://github.com/Daniel-Abrecht/librem5-image-builder/blob/master/src/make-helper-functions.mk

Das Hauptmakefile, dass aus allen Komponenten die Images baut:
https://github.com/Daniel-Abrecht/librem5-image-builder/blob/master/makefile

Das Hauptmakefile führt dann noch die Makefiles zum bauen der 
Komponenten aus.

Beim Kernel ist das einfach repo clonen, config file anlegen, und dann 
das Makefile des Kernelrepos mit den entsprechenden Parametern fürs 
crosscompiling ausführen:
https://github.com/Daniel-Abrecht/librem5-image-builder/tree/master/kernel

Beim u-boot ist dass dann viel Komplizierter, da muss ich noch Firmware 
und weitere Projekte holen, zeug rumkopieren sonstige Tools aufrufen, 
usw.
https://github.com/Daniel-Abrecht/librem5-image-builder/blob/master/uboot/makefile

Und für andere debian Packete, die ich cross compiliert noch so brauche, 
hab ich ein allgemeines Makefile, wo ich erst noch das Buildenvironment 
usw. generieren lassen muss:
https://github.com/Daniel-Abrecht/librem5-image-builder/blob/master/chroot-build-helper/makefile

Die verschiedenen dinge müssen derart unterschiedlich gebaut werden, nur 
ein Makefile ist da einfach nicht sinnvoll.


Was komplett anderes war das ding: 
https://github.com/Daniel-Abrecht/dpaparser

Da hatte ich parser code von nem Template generieren lassen, durch den C 
preprozessor. Brauchte sowas dann noch bei nem anderen Projekt, also 
ausgelagert. Das ist ein Programm oder Script, bei dem es sich um ein 
Makefile handelt.


Und dann gibt es noch Situationen wie beim Linux Kernel, wo man 
auswählen kann, welche Teile man wie bauen will. Das nutzt dort die 
schon erwähnte Methode, die Sourcen der Komponenten in dessen 
Verzeichnis aufzulisten, plus noch Abhängigkeitskram.


Projekte sind nicht immer nur ein simples allen Quellcode durch den 
Compiler jagen und fertig.

von Vincent H. (vinci)


Lesenswert?

DPA schrieb:
> Es gibt viele verschiedene Gründe und Strategien, die mehrere Makefiles
> rechtfertigen.
>
> etc.

Richtig, hab ich ja auch nie angezweifelt.

Das simple Zusammensuchen von Source-Datein aus Unterordner ist aber 
imho eben kein so ein Grund.

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.