2016-07-14 12 views
1

Ich arbeite an einem Makefile für ein C++ - Projekt, das einige Konfigurationen, d. H. Debug, Release und vielleicht ein paar mehr kundenspezifische in der Zukunft unterstützen muss.Makefile Pattern-Regel: Circular Makefile.o <- Makefile Abhängigkeit gelöscht

Derzeit ist meine Namenskonvention für generierte .o-Dateien $(SOURCE_FULLPATH).$(CONFIGURATION).o. Zum Beispiel erzeugt ABC.cppABC.cpp.debug.o im Debug-Modus.

Jetzt möchte ich die Musterregel für die Generierung dieser Objektdateien in einer konfigurationsunabhängigen Art und Weise schreiben. Was ich tat war: von jedem XX.o Dateiname, strippe ich das .debug oder .release Suffix von XX, und verwende den restlichen Teil von XX als Quelldateiname.

%.o: $$(basename %) 
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o [email protected] $< 

Mit diesem Trick kann ich die ausführbare Datei korrekt bauen, mit der Ausnahme, dass ich eine Warnmeldung von make erhalten:

make: Circular makefile.o <- makefile dependency dropped. 

ich verwirrt bin, weil ich als Ziel nicht makefile oder makefile.o Liste oder Abhängigkeit irgendwo in meinem Makefile. Ich habe eine Suche nach SO durchgeführt, aber die meisten Fragen zur Circular-Abhängigkeit beziehen sich auf eine bestimmte Benutzerquelldatei und nicht auf das Makefile selbst. Kann mir jemand helfen zu verstehen, was die zirkuläre Abhängigkeit verursacht und wie man diese Warnmeldung los wird?

Ein Beispielmakefile, das dieses Problem reproduzieren kann, ist unten aufgeführt.

.SECONDEXPANSION: 

PROJECT := helloworld 
CC := clang++ 
BUILD_FOLDER := Build 
OBJ_FILE_SUFFIX := .o 

# Source 
CPP_FILES :=\ 
    Source/hello.cpp \ 
    Source/mysqrt.cpp \ 

INCLUDE_FOLDERS := \ 
    -IInclude 

# MMD outputs the dependency files (".d" files). These files will be used by 
# this makefile to allow for dependency checking on .h files. 
CC_FLAGS += -MMD 

EXISTING_OBJ_FILES = $(wildcard $(addsuffix *.o, $(basename $(CPP_FILES)))) 

##-------------------- 
## Targets definition 
##-------------------- 
.PHONY:default 
default: all 

.PHONY:all 
all: debug release 

.PHONY:debug release 
# Add a 'debug'/'release' suffix to the name of the object file 
# e.g. hello.cpp -> hello.cpp.debug.o 
debug release: OBJ_FILES=$(addsuffix [email protected]$(OBJ_FILE_SUFFIX), $(CPP_FILES)) 
debug release: $${OBJ_FILES} # Use Secondary Expansion to get the obj names 
    $(CC) $^ -o $(BUILD_FOLDER)/$(PROJECT)[email protected] 

# Strip configuration name from the end of the object file name 
%.o: $$(basename %) 
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o [email protected] $< 

## clean: remove executable, all object files, and all dependency files 
.PHONY:clean 
clean: 
    -rm -f $(BUILD_FOLDER)/$(PROJECT) $(EXISTING_OBJ_FILES) $(EXISTING_OBJ_FILES:.o=.d) 

# Include the dependent files so that in later builds, modified .h files 
# will cause all .cpp dependent on them to rebuild 
-include $(OBJ_FILES:.o=.d) 

Die Ordnerstruktur ist

makefile 
Source 
- hello.cpp 
- mysqrt.cpp 
Include 
- mysqrt.h 

Die vollständige Ausgabe von make debug ist

make: Circular makefile.o <- makefile dependency dropped. 
clang++ -MMD -IInclude -c -o Source/hello.cpp.debug.o Source/hello.cpp 
clang++ -MMD -IInclude -c -o Source/mysqrt.cpp.debug.o Source/mysqrt.cpp 
clang++ Source/hello.cpp.debug.o Source/mysqrt.cpp.debug.o -o Build/helloworld_debug 

Alles, außer für die erste Zeile ist gut.

Ich würde es auch wirklich schätzen, wenn jemand auf mich zeigen kann, wenn es eine schlechte Praxis in meinem Makefile gibt (ich bin immer noch ein Neuling im Makefile). Vielen Dank im Voraus!

Antwort

2

GNU Make versucht immer, die Makefile (s) zu aktualisieren, die es vor gelesen hat. Wenn es Regeln und Voraussetzungen findet, die es anweisen, Makefile (s) zu aktualisieren, dann tut es das und startet dann erneut von Grund auf neu - einschließlich versuchen, die Makefile (s) zu aktualisieren. Siehe 3.5 How Makefiles Are Remade.

In Ihrem Rezept:

%.o: $$(basename %) 
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o [email protected] $< 

Sie haben make mit einer Regel zur Verfügung gestellt makefile.o von makefile zu machen.

Es ist auch die Umkehrung der Regel in dem builtin Rezepte

%: %.o 
    $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o [email protected] 

, die eine ausführbare Datei aus einer einzigen Objektdatei macht.So hat Ihr Rezept die Zirkularität eingeführt:

makefile.o <- makefile <- makefile.o 

wenn makemakefile erwägt sich als Ziel. Sie könnten die Zirkularität unterdrücken, indem ausdrücklich die eingebaute inverse Regel zu löschen, durch die leere Regel schreiben:

%: %.o 

in der Make-Datei. Dann könnten Sie die folgende Verwirrung auf Seiten des Compiler beobachten:

$ make makefile.o 
clang++ -c -o makefile.o makefile 
clang: warning: makefile: 'linker' input unused 

Und das gleiche würde auftreten, wenn Sie ein Ziel zu machen versucht, die auf makefile.o abhing.

Es ist wahrscheinlich davon auszugehen, dass Sie keine Ziele haben werden, die von makefile.o abhängen. Dennoch ist eine Regel, die kompilieren würde foo.o von jeder vorhandenen Datei foo ist deutlich mehr, dass Sie wollen oder müssen. Für das spezielle Muster der Abhängigkeit, die Sie erfassen möchten:

foo.cpp.{debug|release}.o: foo.cpp 

würden Sie besser dran mit:

%.o: $$(basename $$(basename %)).cpp 
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o [email protected] $< 

Hinweis, BTW, dass in GNU Konventionen Machen - die Konventionen, die angenommen sind von GNU Machen eingebaute Regeln - CC bezeichnet Ihren C-Compiler, während CXX Ihren C++ - Compiler bezeichnet. Gleichermaßen sind Flags für den C-Compiler mit CFLAGS bezeichnet und Flags für den C++ - Compiler sind mit CXXFLAGS bezeichnet.

Flags für den Präprozessor sind CPPFLAGS bezeichnet und -IWeg Optionen - die Vorverarbeitungsbefehle sind - werden üblicherweise durch CPPFLAGS weitergegeben werden.