Vor einigen Monaten habe ich mir das folgende Generikum Makefile
für Schulaufgaben ausgedacht:
# ------------------------------------------------
# Generic Makefile
#
# Author: [email protected]
# Date : 2010-11-05
#
# Changelog :
# 0.01 - first version
# ------------------------------------------------
# project name (generate executable with this name)
TARGET = projectname
CC = gcc -std=c99 -c
# compiling flags here
CFLAGS = -Wall -I.
LINKER = gcc -o
# linking flags here
LFLAGS = -Wall
SOURCES := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS := $(SOURCES:.c=*.o)
rm = rm -f
$(TARGET): obj
@$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS)
@echo "Linking complete!"
obj: $(SOURCES) $(INCLUDES)
@$(CC) $(CFLAGS) $(SOURCES)
@echo "Compilation complete!"
clean:
@$(rm) $(TARGET) $(OBJECTS)
@echo "Cleanup complete!"
Dies kompiliert grundsätzlich jede .c
und .h
Datei zu erzeugen , .o
Dateien und die ausführbare Datei projectname
alle im selben Ordner.
Jetzt möchte ich das ein wenig vorantreiben. Wie kann ich ein Makefile schreiben, um ein C-Projekt mit der folgenden Verzeichnisstruktur zu kompilieren?
./
./Makefile
./src/*.c;*.h
./obj/*.o
./bin/<executable>
Mit anderen Worten, ich hätte gerne ein Makefile, das C-Quellen aus ./src/
in kompiliert ./obj/
und dann alles verknüpft, um die ausführbare Datei in zu erstellen ./bin/
.
Ich habe versucht, verschiedene Makefiles zu lesen, aber ich kann sie einfach nicht für die obige Projektstruktur verwenden. Stattdessen kann das Projekt nicht mit allen möglichen Fehlern kompiliert werden. Sicher, ich könnte eine ausgewachsene IDE (Monodevelop, Anjuta usw.) verwenden, aber ich ziehe es ehrlich gesagt vor, bei gEdit und dem guten alten Terminal zu bleiben.
Gibt es einen Guru, der mir eine funktionierende Lösung geben kann oder klare Informationen darüber, wie dies getan werden kann? Danke dir!
** UPDATE (v4) **
Das finale Resultat :
# ------------------------------------------------
# Generic Makefile
#
# Author: [email protected]
# Date : 2011-08-10
#
# Changelog :
# 2010-11-05 - first version
# 2011-08-10 - added structure : sources, objects, binaries
# thanks to http://stackoverflow.com/users/128940/beta
# 2017-04-24 - changed order of linker params
# ------------------------------------------------
# project name (generate executable with this name)
TARGET = projectname
CC = gcc
# compiling flags here
CFLAGS = -std=c99 -Wall -I.
LINKER = gcc
# linking flags here
LFLAGS = -Wall -I. -lm
# change these to proper directories where each file should be
SRCDIR = src
OBJDIR = obj
BINDIR = bin
SOURCES := $(wildcard $(SRCDIR)/*.c)
INCLUDES := $(wildcard $(SRCDIR)/*.h)
OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
rm = rm -f
$(BINDIR)/$(TARGET): $(OBJECTS)
@$(LINKER) $(OBJECTS) $(LFLAGS) -o $@
@echo "Linking complete!"
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
@$(CC) $(CFLAGS) -c $< -o $@
@echo "Compiled "$<" successfully!"
.PHONY: clean
clean:
@$(rm) $(OBJECTS)
@echo "Cleanup complete!"
.PHONY: remove
remove: clean
@$(rm) $(BINDIR)/$(TARGET)
@echo "Executable removed!"
Makefile
. Ich komme näher, aber ich habe Probleme mit den automatischen Variablen, also scheint es trotzdemAntworten:
Erstens ist Ihre
$(OBJECTS)
Regel problematisch, weil:file1.o
und entdeckt habenfile2.o
)foo.o
) entspricht nicht dem, was die Regel tatsächlich erzeugt (obj/foo.o
).Ich schlage folgendes vor:
Die
$(TARGET)
Regel hat das gleiche Problem, dass der Zielname nicht beschreibt, was die Regel erstellt. Wenn Siemake
mehrmals eingeben, erstellt Make das Ziel aus diesem Grund jedes Mal neu, auch wenn es keinen Grund dafür gibt. Eine kleine Änderung behebt Folgendes:Sobald alles in Ordnung ist, können Sie eine komplexere Behandlung von Abhängigkeiten in Betracht ziehen. Wenn Sie eine der Header-Dateien ändern, weiß dieses Makefile nicht, welche Objekte / ausführbaren Dateien neu erstellt werden müssen. Aber das kann auf einen anderen Tag warten.
EDIT:
Entschuldigung, ich habe einen Teil der
$(OBJECTS)
obigen Regel weggelassen . Ich habe es korrigiert. (Ich wünschte, ich könnte "Strike" in einem Codebeispiel verwenden.)quelle
obj/file1.o: In function 'main': \n main.c:(.text+0x0): multiple definition of 'main' \n obj/main.o:main.c:(.text+0x0): first defined here
main
Funktionen? Vielleicht eins reinfile1.c
und eins reinmain.c
? In diesem Fall können Sie diese Objekte nicht verknüpfen. Es kann nur einemain
in einer ausführbaren Datei geben.file1.c
aber es gibt die gleiche Nachricht für jede einzelne Datei des Projekts. Undmain.c
ist der einzige mit einer Hauptfunktion ... undmain.c
importiertfile1.h
undfile2.h
(es gibt keine Beziehung zwischenfile1.c
undfile2.c
), aber ich bezweifle, dass das Problem von dort kommt.$(OBJECTS)
Regel eingefügt habe . Ich habe es bearbeitet. Mit der schlechten Linie habe ich einen Fehler bekommen, aber nicht den, den du bekommen hast ...Sie können das
-I
Flag zu den Compiler-Flags (CFLAGS) hinzufügen, um anzugeben, wo der Compiler nach Quelldateien suchen soll, und das Flag -o, um anzugeben, wo die Binärdatei verbleiben soll:obj
Verwenden Sie-o
beim Kompilieren die Option , um die Objektdateien im Verzeichnis abzulegen. Schauen Sie sich auch die$@
und$<
automatische Variablen an .Betrachten Sie beispielsweise dieses einfache Makefile
Update>
Wenn ich mir dein Makefile ansehe, merke ich, dass du die
-o
Flagge benutzt. Gut. Verwenden Sie es weiterhin, fügen Sie jedoch eine Zielverzeichnisvariable hinzu, um anzugeben, wo die Ausgabedatei geschrieben werden soll.quelle
-l ...
zuCFLAGS
und ... es gibt bereits das-o
Argument zum Linker (LINKER
)make
, von wo das Makefile sitztIch habe in diesen Tagen aufgehört, Makefiles zu schreiben. Wenn Sie lernen möchten, machen Sie weiter, sonst haben Sie einen guten Makefile-Generator, der mit Eclipse CDT geliefert wird. Wenn Sie in Ihrem Build-Baum eine gewisse Wartbarkeit / Unterstützung für mehrere Projekte wünschen, sehen Sie sich Folgendes an:
https://github.com/dmoulding/boilermake Ich fand das ziemlich gut ..!
quelle