Ich bin sehr neu in Makefiles und ich möchte Verzeichnisse mit Makefile erstellen. Mein Projektverzeichnis ist so
+--Project
+--output
+--source
+Testfile.cpp
+Makefile
Ich möchte alle Objekte und Ausgaben in den jeweiligen Ausgabeordner legen. Ich möchte eine Ordnerstruktur erstellen, die nach dem Kompilieren so aussehen würde.
+--Project
+--output
+--debug (or release)
+--objs
+Testfile.o
+Testfile (my executable file)
+--source
+Testfile.cpp
+Makefile
Ich habe es mit mehreren Optionen versucht, konnte aber nicht erfolgreich sein. Bitte helfen Sie mir, Verzeichnisse mit make file zu erstellen. Ich poste mein Makefile für Ihre Überlegung.
#---------------------------------------------------------------------
# Input dirs, names, files
#---------------------------------------------------------------------
OUTPUT_ROOT := output/
TITLE_NAME := TestProj
ifdef DEBUG
TITLE_NAME += _DEBUG
else
ifdef RELEASE
TITLE_NAME += _RELEASE
endif
endif
# Include all the source files here with the directory tree
SOURCES := \
source/TestFile.cpp \
#---------------------------------------------------------------------
# configs
#---------------------------------------------------------------------
ifdef DEBUG
OUT_DIR := $(OUTPUT_ROOT)debug
CC_FLAGS := -c -Wall
else
ifdef RELEASE
OUT_DIR := $(OUTPUT_ROOT)release
CC_FLAGS := -c -Wall
else
$(error no build type defined)
endif
endif
# Put objects in the output directory.
OUT_O_DIR := $(OUT_DIR)/objs
#---------------------------------------------------------------------
# settings
#---------------------------------------------------------------------
OBJS = $(SOURCES:.cpp=.o)
DIRS = $(subst /,/,$(sort $(dir $(OBJS))))
DIR_TARGET = $(OUT_DIR)
OUTPUT_TARGET = $(OUT_DIR)/$(TITLE_NAME)
CC_FLAGS +=
LCF_FLAGS :=
LD_FLAGS :=
#---------------------------------------------------------------------
# executables
#---------------------------------------------------------------------
MD := mkdir
RM := rm
CC := g++
#---------------------------------------------------------------------
# rules
#---------------------------------------------------------------------
.PHONY: all clean title
all: title
clean:
$(RM) -rf $(OUT_DIR)
$(DIR_TARGET):
$(MD) -p $(DIRS)
.cpp.o:
@$(CC) -c $< -o $@
$(OBJS): $(OUT_O_DIR)/%.o: %.cpp
@$(CC) -c $< -o $@
title: $(DIR_TARGET) $(OBJS)
Danke im Voraus. Bitte führe mich, wenn ich auch Fehler gemacht habe.
output/debug', needed by
erstellen. Stop." Aber darüber werde ich mir jetzt keine Sorgen machen. wird sich an die Grundregeln halten. :). Vielen Dank für die Anleitung. Und ich führe "make" nur aus dem Toplevel-Verzeichnis aus.directories
ohne dass diese immer neu erstellt werden.Meiner Meinung nach sollten Verzeichnisse weder im technischen noch im gestalterischen Sinne als Ziele Ihres Makefiles betrachtet werden. Sie sollten erstellen Dateien und wenn eine Datei erstellen ein neues Verzeichnis muss dann ruhig das Verzeichnis in der Regel für die entsprechende Datei erstellen.
Wenn Sie auf eine normale oder "gemusterte" Datei abzielen, verwenden Sie einfach die
make
interne Variable$(@D)
, dh "das Verzeichnis, in dem sich das aktuelle Ziel befindet" (cmp. Mit$@
für das Ziel). Beispielsweise,Dann machen Sie effektiv dasselbe: Erstellen Sie Verzeichnisse für alle
$(OBJS)
, aber Sie tun es auf weniger komplizierte Weise.Dieselbe Richtlinie (Dateien sind Ziele, Verzeichnisse niemals) wird in verschiedenen Anwendungen verwendet. Beispielsweise
git
speichert das Revisionskontrollsystem keine Verzeichnisse.Hinweis: Wenn Sie es verwenden möchten, kann es hilfreich sein, eine Convenience-Variable einzuführen und die
make
Erweiterungsregeln zu verwenden.quelle
Oder KISS.
Dadurch werden alle Verzeichnisse erstellt, nachdem das Makefile analysiert wurde.
quelle
$(info $(shell mkdir -p $(DIRS)))
Ohne das$(info ...)
wird die Ausgabe desmkdir
Befehls in das Makefile eingefügt , was bestenfalls zu Syntaxfehlern führt. Der$(info ...)
Aufruf stellt sicher, dass a) die Fehler (falls vorhanden) für den Benutzer sichtbar sind und b) der Funktionsaufruf zu nichts erweitert wird.make
In und Off selbst werden Verzeichnisziele genauso behandelt wie Dateiziele. Es ist also einfach, Regeln wie diese zu schreiben:Das einzige Problem dabei ist, dass der Zeitstempel des Verzeichnisses davon abhängt, was mit den darin enthaltenen Dateien gemacht wird. Für die obigen Regeln führt dies zu folgendem Ergebnis:
Dies ist definitiv nicht das, was Sie wollen. Wenn Sie die Datei berühren, berühren Sie auch das Verzeichnis. Und da die Datei vom Verzeichnis abhängt, scheint die Datei veraltet zu sein, sodass sie neu erstellt werden muss.
Sie können diese Schleife jedoch leicht unterbrechen, indem Sie make anweisen, den Zeitstempel des Verzeichnisses zu ignorieren . Dies erfolgt durch Deklarieren des Verzeichnisses als Voraussetzung nur für Bestellungen:
Dies ergibt richtig:
TL; DR:
Schreiben Sie eine Regel, um das Verzeichnis zu erstellen:
Und hängen die Ziele für das darin enthaltene Material nur von der Reihenfolge des Verzeichnisses ab:
quelle
touch
Stat-Daten im übergeordneten Verzeichnis geändert? Das macht für mich keinen Sinn. Die Zeit eines Verzeichnisses hängt nur von den darin enthaltenen Dateinamen ab. Ich konnte Ihr Problem nicht reproduzieren.Alle Lösungen, einschließlich der akzeptierten, weisen einige Probleme auf, wie in den jeweiligen Kommentaren angegeben. Die akzeptierte Antwort von @ jonathan-leffler ist bereits recht gut, berücksichtigt jedoch nicht, dass die Voraussetzungen nicht unbedingt in der richtigen Reihenfolge (während) erstellt werden müssen
make -j
zum Beispiel ) erstellt werden müssen. Wenn Sie jedoch einfach diedirectories
Voraussetzung von verschieben,all
umprogram
bei jedem AFAICT-Lauf Neuerstellungen zu provozieren. Die folgende Lösung hat dieses Problem nicht und AFAICS funktioniert wie beabsichtigt.quelle
Ich habe gerade eine ziemlich vernünftige Lösung gefunden, mit der Sie die zu erstellenden Dateien definieren und Verzeichnisse automatisch erstellen lassen können. Definieren Sie zunächst eine Variable
ALL_TARGET_FILES
, die den Dateinamen jeder Datei enthält, die Ihr Makefile erstellen soll. Verwenden Sie dann den folgenden Code:So funktioniert das. Ich definiere eine Funktion
depend_on_dir
die einen Dateinamen annimmt und eine Regel generiert, die die Datei von dem Verzeichnis abhängig macht, in dem sie enthalten ist, und definiere dann eine Regel, um dieses Verzeichnis bei Bedarf zu erstellen. Dann benutze ich ,foreach
umcall
diese Funktion auf jeden Dateinamen undeval
das Ergebnis.Beachten Sie, dass Sie eine Version von GNU make benötigen, die unterstützt
eval
. Ich denke, es handelt sich um Versionen 3.81 und höher.quelle
Da Sie ein Neuling sind, würde ich sagen, versuchen Sie dies noch nicht. Es ist definitiv möglich, wird aber Ihr Makefile unnötig komplizieren. Halten Sie sich an die einfachen Methoden, bis Sie sich mit make besser auskennen.
Eine Möglichkeit, ein anderes Verzeichnis als das Quellverzeichnis zu erstellen , ist VPATH . Ich bevorzuge Musterregeln
quelle
Die Unabhängigkeit des Betriebssystems ist für mich von entscheidender Bedeutung und daher
mkdir -p
keine Option. Ich habe diese Reihe von Funktionen erstellt,eval
mit denen Verzeichnisziele mit der Voraussetzung für das übergeordnete Verzeichnis erstellt werden. Dies hat den Vorteil, dass diesmake -j 2
problemlos funktioniert, da die Abhängigkeiten korrekt ermittelt werden.Wenn Sie beispielsweise Folgendes ausführen, wird Folgendes erstellt:
quelle
Siehe https://www.oreilly.com/library/view/managing-projects-with/0596006101/ch12.html
Da ich Ubuntu verwende, musste ich dies auch oben in meinem Makefile hinzufügen:
quelle