2016-07-14 231 views
1

我正在爲一個C++項目製作一個makefile,這個項目需要支持一些配置,即調試,發佈以及將來可能還有一些定製的配置。Makefile模式規則:循環makefile.o < - makefile依賴項被刪除

目前,我生成的.o文件的命名約定是$(SOURCE_FULLPATH).$(CONFIGURATION).o。例如,ABC.cpp以調試模式生成ABC.cpp.debug.o

現在我想編寫用於以獨立於配置的方式生成這些對象文件的模式規則。我所做的是:從每個XX.o文件名,我剝去.debug.release後綴XX,並使用XX的剩餘部分作爲源文件名。

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

有了這一招,我可以正確生成可執行,但我從make得到一個警告消息:

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

我百思不得其解,因爲我不列出makefilemakefile.o作爲目標或依賴於我的makefile中的任何地方。我對SO進行了搜索,但大多數關於循環依賴的問題都在特定的用戶源文件上,而不是makefile本身。 任何人都可以幫助我理解導致循環依賴的原因,以及如何擺脫此警告消息

下面列出了一個可以重現此問題的示例makefile。

.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) 

的文件夾結構是

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

make debug的全部輸出是

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 

一切是除了第一行良好。

如果任何人在我的makefile中有任何不好的做法(我仍然是makefile中的新手),任何人都可以指向我,我也會很感激。先謝謝你!

回答

2

GNU Make總是嘗試更新它在 之前讀取的任何其他文件。如果它發現規則和先決條件告訴它更新生成文件,則它會這樣做,然後再次從頭開始 - ,包括嘗試更新生成文件。見3.5 How Makefiles Are Remade

在你的食譜:

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

您提供make有從makefile使makefile.o的規則。

它也是規則的在內置配方

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

這使得從一個單一的對象文件的可執行的倒數。所以,你的食譜已經推出了圓:

makefile.o <- makefile <- makefile.o 

make考慮makefile本身作爲目標。 你可以通過編寫空規則明確刪除內置的逆規則, 抑制圓:

%: %.o 
在makefile

。然後,你可以遵循以下混亂的 編譯器的部分:

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

如果你試圖使上makefile.o依賴 任何目標同樣會發生。

假設您不會有依賴於 makefile.o的目標。儘管如此,從任何現有文件foo嘗試 編譯foo.o的規則顯然更清晰,您 想要或需要。對於希望捕捉到依賴的特定模式:

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

你會用更好:

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

注意,順便說一句,在GNU使公約 - 這是 承擔的約定通過GNU Make的內置規則 - CC表示您的C編譯器,而 CXX表示您的C++編譯器。同樣,C編譯器的標誌是 ,表示爲CFLAGS,而C++編譯器的標誌表示爲CXXFLAGS

標誌爲預處理器被表示CPPFLAGS,和-I路徑選項 - 這是預處理器的選擇 - 常規通過CPPFLAGS傳遞。