[gmake] Header Abhängigkeit

rubricanis

Homo ludens
Langsam - wenn auch mühselig - gewöhnen ich mich ja an gmake. Was ich noch nicht hinbekomme ist die Abhängigkeit von header files. Ein Beispiel aus einem Submakefile:
Code:
target := $(bin)/myapp

header := \
   $(include)/common.hpp

objects := \
   $(build)/main.o

# targets
$(target): $(build)  $(objects)
   @echo == creating app ===
   $(silent)$(cxx) -o $(target) $(flags) $(objects) $(libs)

$(build)/%.o: $(src)/%.cpp
   $(silent)$(cxx) -c $(flags) -I$(include) -o $@ $<

$(build):
   $(silent) mkdir -p $@
Ich hatte u.A. vermutet das folgendes funktioniert:
Code:
$(build)/%.o: $(src)/%.cpp $(header)
   $(silent)$(cxx) -c $(flags) -I$(include) -o $@ $<
Aber das ist nicht der Fall. Wie macht man das also ?
 
Es ist seltsam, nicht lange nachdem man eine Frage gepostet hat, stößt man endlich auf die Lösung... :cool:

Hat sich also erledigt. Sorry for the noise !
 
Da hab ich mich zu früh gefreut.So lange man bei einem Versuchs-Setup auf einer Ebene bleibr funktioniert folgendes:
Code:
depend := myapp.d
...
depend:
   @$(cxx) $(flags) -MM $(src)/*.cpp > $(depend)

include $(depend)
Wenn ich das allerdings in einem Submake mache - zb. myapp/myapp.mk, - funktioniert das nicht mehr, zumindest wenn ich ein build Verzeichnis verwende. Der Grund ist dass im depend file schlicht myapp.o .<pfade> steht, ohne jeden Pfad. Wie es scheint ist das wohl nur über einen ziemlich kryptischen sed Befehl zu lösen der die Pfade einfügt.
http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
Aber da will ich nicht ran, mit regex & co stehe ich eh auf Kriegsfuß und Sachen die ich nicht wirklich verstehe lasse ich lieber. Außerdem habe ich noch nicht herausgefunden wie man SubMakefile depend von Makefile depend aus aufruft. Was also bleibt ?
(1) Die Abhängigkeiten im Submakefile per Hand einsetzen ? Geht vermutlich, ist aber nicht Sinn der Sache.
(2) Statt direktem Aufruf vom Makefile könnte ich evtl. cd SubMakefile machen und das direkt aufrufen. Hmmm, müßte alles umgebaut werden und ob es funktioniert ???
(3) Cmake verwenden. Na ja, genau so ein heftiges Ding wie make das ich auch erst lernen muss.:( Vermutlich die beste Lösung.

Oder gibt es noch eine andere Lösung ?

Peter
 
Also ich mache es so (grob skizziert):

Der Compiler erzeugt mir mit -MMD die Abhängigkeiten. Man kann auch externe Tools nutzen, aber meiner Erfahrung nach hat der Compiler die beste Sicht auf den Code und laufen muss er sowieso. Tut also niemanden weh:
Code:
CFLAGS := -MMD -std=c99 -Wall -Werror -pedantic

Im Makefile serviere ich gmake eine List der zu erstellenden Objekte:
Code:
OBJS_ = \
    src/file1.o \
    src/file2.o

Die Objekte werden automatisiert auf das Object-Dir umgebogen, sodass die Objekte nicht den Code vergödeln:
Code:
OBJS = $(patsubst %,build/%,$(OBJS_))

Daraus generiere ich dann die Header-Dependencies und saugen sie ein, sofern vorhanden:
Code:
DEPS = $(OBJS:.o=.d)
-include $(DEPS)

Die eigentliche Magie ist dann in der Converter-Rule, die magisch die Sourcen aus dem korrekten Verzeichnis lädt und Objekte sowie Dependency-Dateien ins Objekt-Verzeichnis schreibt:
Code:
build/%.o: %.c
   @echo "===> CC $<"
   $(Q)mkdir -p $(@D)
   $(Q)$(CC) -c $(INCLUDE) $(CFLAGS) -o $@ $<

Das sollte auch alles wunderbar zwischen Submakefiles, großen Verzeichnishierarchien und so weiter funktionieren. Du musst nur aufpassen, nicht mit den Verzeichnisebenen durcheinander zu kommen.
 
@Kamikaze: Hatte ich auch schon einmal kurz reingeschaut. Mir schien aber dass der Weg über den Compiler selbst besser ist.

@Yamagi
Du machst mir Hoffung! :) Werde ich heute Abend/Morgen weiter verfolgen. Jetzt scheint die Sonne und ich werde mich erst einmal daran machen unser Restholz zu zersägen. Körperliche Arbeit klärt die Birne! :)

Danke!
 
Ich kenne mich mit awk, sed etc nicht aus. Ich hatte auch daran gedacht mir etwas ähnliches in Lua zu schreiben, mir die deps mit makedeps zu holen und und in Lua weiter zu verarbeiten was vermutlich kein größeres Problem ist. Aber gmake Lösungen haben den entscheidenden Vorzug halbwegs portabel zu sein.Und den potentiellen user daran zu binden andere Werkzeuge zu installieren ist schon ein wenig daneben. Obwohl mein Projekt noch in der Konzeptions- und Versuchsphase steckt möchte ich doch von vorneherein eine vernünftige Struktur haben. Man weiß ja nie was daraus wird...

Außerdem ist es nicht schlecht neues zu lernen, muss ja nicht gleich die ganze unix toolbox sein.:rolleyes:
 
Yamagi, works like a charm! :) Solltest du mal in die Gegend von Wien kommen gebe ich einen kräftigen aus!

Aber jetzt lass mich bitte nicht dumm sterben. Die eigentliche Magie liegt ja hierin:
Code:
depend := $(objects:.o=.d)
-include $(depend)
Das include ist klar, aber was macht depend := $(objects:.o=.d) ???
 
Es erstellt eine neue Variable 'depend', dessen Inhalt dem vom 'objects' entspricht. Nur das dort die Zeichenfolge .o durch .d ersetzt wurde. Als Beispiel: Vorher hast du 'build/src/file.o', hinterher 'build/src/file.d'. Der Trick ist, dass der Compiler die Objektdatei mit Endung .o ausspuckt und dazu eine Datei mit Abhängigkeiten, die auf .d endet. Durch das Umschreiben bekommen wir sie automatisch gmake bekannt gemacht.
 
Zum Beispiel im Makefile von yquake2 ist es komplett umgesetzt: https://github.com/yquake2/yquake2/blob/master/Makefile Das ist allerdings durch die diversen Sonderlocken für MinGW auf Windows und OS X Spezialitäten beim Linken abartig kompliziert und nicht mehr unbedingt leicht zu verstehen.

Allgemein gesagt spart mein Ansatz sich auch einen Schritt, der mir damals überflüssig erschien. Das verwirrt vielleicht. Man schreibt die Datei mit der Endung .o in die Objektliste, also 'src/file.o'. Korrekter wäre, entweder gleich 'build/src/file.o' zu schreiben und die Pfade nicht automatisch anzupassen. Oder alternativ 'src/file.c' und einen weiteren Übersetzungsschritt einzufügen, der zuerst das 'src/file.o' baut. Aber das wirklich nur am Rand, bringe es erstmal grundsätzlich zum Laufen.
 
..., bringe es erstmal grundsätzlich zum Laufen.
Klar, ich denke auch das mich das weit tragen wird. Verschiedenen Varianten habe ich im Haupt-Makefile und entsprechende Defs schon vorgesehen.

Ich bin dem ganzen noch etwas nachgegangen. Der Schlüssel liegt im -MMD flag das ich noch nicht kannte.

Vielen Dank noch einmal!

Peter
 
Zurück
Oben