• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

Probleme beim Makefile-schreiben

Delryn

Newbie
Hallo!

Ich bin absolut neu was Makefiles angeht.
Zum einen wüsste ich gerne, wie ich Text ausgebe. Ich hab gesucht, aber alle Varianten klappen nicht, Meldung:

Missing Seperator.

@echo Text
echo Text
echo "Text"
usw. :roll: ;)

Zweitens bekomme ich mein Programm nicht compiliert, hier das Makefile:

Code:
CFG=Debug


#####################
# Debug-Konfiguration
#####################
ifeq "$(CFG)" "Debug"


OUTDIR=Debug
OUTFILE=$(OUTDIR)/app
QTLIB=-L/usr/local/Trolltech/Qt-4.1.0/lib
QTINCLUDE=-I/usr/local/Trolltech/Qt-4.1.0/include 
USEDLIBS=-lqtmain


OBJECTS=$(OUTDIR)/CMainWindow.o \
	$(OUTDIR)/main.o \
	$(OUTDIR)/ui_MainWindow.o

app : $(OBJECTS)
	gcc -o app $(OBJECTS)
	
CMainWindow.o : CMainWindow.h CMainWindow.cpp
	gcc -c CMainWindow.cpp
	
main.o :
	gcc -c main.cpp
	
ui_MainWindow.o : ui_MainWindow.h
	gcc -c ui_MainWindow.h	


clean :
	rm -f $(OBJECTS)
	rm -f $(OUTFILE)

endif


make: *** No rule to make target `Debug/CMainWindow.o', needed by `app'. Stop.


Ich hangel mich dabei durch die "GNU Make"-Beispiele, aber wie man sieht bekomme ich das nicht hin. Wäre nett, wenn mir jemand helfen würde :)
 
Steht doch da: Gebaut wird das Target "app" (weil es das erste ist) und dieses setzt das Target "Debug/CMainWindow.o" voraus, dafür gibt es jedoch keine Regel. Du hast ledigliche eine Regel für "CMainWindow.o" erstellt, "CMainWindow.o" ist jedoch etwas anderes als "Debug/CMainWindow.o".

Du müsstest die Regeln so abändern, dass "$(OUTDIR)" richtig gehandhabt wird. Möglicherweise hilfreiches Stichwort: "VPATH" (darüber müsste mehr in den Info-Seiten zu finden sein)

PS: Das andere Problem ("Missing Seperator") hat garantiert etwas mit Whitespace zu tun. Beachte, dass Tabs und Leerzeichen in Makefiles nicht austauschbar sind und eine unterschiedliche Bedeutung haben. Wahrscheinlich hast Du an einer Stelle das eine verwendet, wo eigentlich das andere hingehört.
 
OP
D

Delryn

Newbie
traffic schrieb:
Du hast ledigliche eine Regel für "CMainWindow.o" erstellt, "CMainWindow.o" ist jedoch etwas anderes als "Debug/CMainWindow.o".

Woher soll ich so etwas wissen?
Wie sieht denn jetzt eine Standard-echo-ausgabe aus? Ich hab die Suche weiterhin benutzt und folgendes gefunden:

@echo "Usage: edit the REAL_DAEMON_DIR definition in the Makefile then:"

Klappt bei mir aber nicht, er sieht usage und then als target an (wegen des Doppelpunktes).


Auf jeden Fall sieht mein Makefile nun so aus:

Code:
CFG=Debug


#####################
# Debug-Konfiguration
#####################
ifeq "$(CFG)" "Debug"


OUTDIR=Debug
OUTFILE=$(OUTDIR)/app
QTLIB=-L/usr/local/Trolltech/Qt-4.1.0/lib
QTINCLUDE=-I/usr/local/Trolltech/Qt-4.1.0/include/
USEDLIBS=-lqtmain


OBJECTS=$(OUTDIR)/CMainWindow.o \
	$(OUTDIR)/main.o \
	$(OUTDIR)/ui_MainWindow.o

# Wie kann ich das OUTFILE compilieren und linken?
OUTFILE : $(OBJECTS)
	gcc -o OUTFILE $(OBJECTS) $(QTINCLUDE) $(USEDLIBS)
	
$(OUTDIR)/CMainWindow.o : CMainWindow.h CMainWindow.cpp
	gcc -c CMainWindow.cpp
	
$(OUTDIR)/main.o :
	gcc -c main.cpp
	
$(OUTDIR)/ui_MainWindow.o : ui_MainWindow.h
	gcc -c ui_MainWindow.h $(QTINCLUDE)


clean :
	rm -f $(OBJECTS)
	rm -f $(OUTFILE)

endif

Meine Frage wäre jetzt, wie die Kommandos aussehen müssten, damit ich OUTFILE compilieren und linken kann.
Ich bekomme immer die Meldung, dass die QT-Header für ui_MainWindow nicht gefunden werden (Der Pfad stimmt aber).
Woran liegt das :)?

Die Handhabung des gcc ist mir völlig fremd, ich hatte halt bisher immer eine IDE die alles für mich zusammengehalten hatte.
 
Delryn schrieb:
Woher soll ich so etwas wissen?
Wie meinen?
Delryn schrieb:
Wie sieht denn jetzt eine Standard-echo-ausgabe aus?
Das hier läuft bei mir wunderbar:
Code:
all:
	@echo "bla: bla:"
Test:
Code:
$ make
bla: bla:
Beachte, dass der Whitespace am Anfang der zweiten Zeile ein Tabulator sein muss.
Delryn schrieb:
Klappt bei mir aber nicht, er sieht usage und then als target an (wegen des Doppelpunktes).
Kann ich nicht reproduzieren. Schau nochmal nach, ob wirklich alle Anführungszeichen korrekt abgeschlossen sind.
Delryn schrieb:
Auf jeden Fall sieht mein Makefile nun so aus:
Eigentlich wollte ich durch Tipps versuchen, dass Du das Problem selbst löst, aber OK, hier die überarbeitete Version:
Code:
CFG = Debug

#####################
# Debug-Konfiguration
#####################
ifeq ($(CFG),Debug)

OUTDIR = Debug
OUTFILE = $(OUTDIR)/app
QTLIB = -L/usr/local/Trolltech/Qt-4.1.0/lib
QTINCLUDE = -I/usr/local/Trolltech/Qt-4.1.0/include
USEDLIBS = -lqtmain

OBJECTS = $(OUTDIR)/CMainWindow.o \
	$(OUTDIR)/main.o \
	$(OUTDIR)/ui_MainWindow.o

$(OUTFILE): $(OBJECTS)
	g++ -o $@ $(OBJECTS) $(QTLIB) $(USEDLIBS)

$(OUTDIR)/CMainWindow.o: CMainWindow.h CMainWindow.cpp
	g++ -I. $(QTINCLUDE) -c -o $@ CMainWindow.cpp

$(OUTDIR)/main.o: main.cpp
	g++ -I. $(QTINCLUDE) -c -o $@ main.cpp

$(OUTDIR)/ui_MainWindow.o: ui_MainWindow.cpp
	g++ -I. $(QTINCLUDE) -c -o $@ ui_MainWindow.cpp

clean:
	rm -f $(OBJECTS)
	rm -f $(OUTFILE)

endif
Wie immer ist zu sagen, dass es selbstverständlich noch unzählige andere Möglichkeiten gibt, das Problem zu lösen. Und zur Klarstellung: Dieses Makefile wird aller Voraussicht nach _nicht_ funkionieren, weil ich das Projekt nicht vorliegen habe und somit nicht testen kann. Aus den Unterschieden kannst Du aber sicherlich erkennen, in welche Richtung es gehen muss.
Delryn schrieb:
Meine Frage wäre jetzt, wie die Kommandos aussehen müssten, damit ich OUTFILE compilieren und linken kann.
Ich bekomme immer die Meldung, dass die QT-Header für ui_MainWindow nicht gefunden werden (Der Pfad stimmt aber).
Woran liegt das :)?
Das liegt daran, dass dem GCC mittels "-I"-Flags mitgeteilt werden muss, in welchem Verzeichnis die Header liegen. Andernfalls findet er sie halt nicht, weil er nicht angewiesen wurde, sie zu suchen.
Delryn schrieb:
Die Handhabung des gcc ist mir völlig fremd, ich hatte halt bisher immer eine IDE die alles für mich zusammengehalten hatte.
Dann schau Dir die Dokumentation des GCC an. Daran führt definitiv kein Weg vorbei. Es ist zu umfangreich, um es im Forum von Grund auf zu behandeln. Lies erstmal was und stell dann konkretere Fragen:
Code:
$ info gcc
$ man gcc
Weitere Hinweise ohne Anspruch auf Vollständigkeit:

- zum Kompilieren von C++-Sourcen immer "g++", nicht "gcc" nehmen. "gcc" geht beim Kompilieren auch, wenn die Dateiendungen stimmen, wird aber spätestens beim Linken nicht mehr klappen

- wenn Du Header-Dateien, die zum Programm selbst gehören, nicht mit '#include <bla.h>', sondern mit '#include "bla.h"' einbindest, kannst Du Dir zumindest einen Teil der "-I."-Flags sparen, weil der GCC dann auch im Source-Verzeichnis automatisch sucht

- das Target, das aus "ui_MainWindow.h" gebaut wird, ist anders gemeint, oder? Wenn Du Header-Dateien direkt kompilierst, erhältst Du standardmäßig kein Objekt (.o) als Ergebnis, sondern einen vorkompilierten Header (.gch), den man keineswegs in eine Anwendung linken kann

- zum Linken brauchst Du keine Include-Flags, die brauchst Du nur zum Kompilieren. Dafür brauchst Du zum Linken die Linker-Flags, diese brauchst Du beim Kompilieren nicht.

- Include-Flags schreibt man normalerweise ganz an den Anfang des GCC-Aufrufs, Linker-Flags kommen ganz ans Ende

- deine Abhängigkeiten sind unvollständig - "main.o" hängt mindestens noch von "main.cpp" ab, wahrscheinlich auch noch von mindestens einer Header-Datei

- der Name des aktuellen Targets steht Dir in der Variable "$@" zur Verfügung, also nutze sie auch der Lesbarkeit zuliebe

- wenn Du den Wert einer Variable meinst, dann verwende auch ihren Wert und nicht die Variable selbst - das ist in Deiner Version falsch ("OUTFILE" vs. "$(OUTFILE)") mit der Konsequenz, dass das fertige Programm immer "OUTFILE" als Namen hat, nicht den Wert dieser Variable

- ...
 
Bevor ich's vergesse, hier noch ein paar Anregungen als nächsten Schritt, nachdem das Makefile erstmal so funktioniert, wie es jetzt ist:

- mehr Variablen nutzen - z.B. "g++" in eine Variable namens "CXX" packen, weil der C++-Compiler keineswegs auf allen Systemen "g++" heißt

- erweiterbare Include- und Linker-Flags nutzen, d.h. die Variablen "QTLIB", "QTINCLUDE", "USEDLIBS" und "-I." durch generische wie "CPPFLAGS" und "LDFLAGS" ersetzen und die erstgenannten dann da reinpacken

- eine Suffix-Regel für die Objekte erstellen, damit nicht jedes Objekt seine eigene Regel braucht - bei drei Objekten vielleicht noch kein Problem, später aber schon, wenn das Projekt größer wird

- eine zusätzliche Regel hinzufügen, die das Output-Verzeichnis automatisch erstellt, falls es noch nicht existiert

- über ein höheres Build-System wie qmake oder autoconf/automake nachdenken - bei drei Source-Dateien wäre es overkill, aber wenn das Projekt größer wird, wirst Du sowas brauchen

- ...
 

TeXpert

Guru
traffic schrieb:
- über ein höheres Build-System wie qmake oder autoconf/automake nachdenken - bei drei Source-Dateien wäre es overkill, aber wenn das Projekt größer wird, wirst Du sowas brauchen

insbesondere bei reinen Qt-Projekten würde ich persönlich immer zu qmake greifen.
 
Oben