2014-09-22 111 views
2

我想爲我的C++程序編寫一個生成文件,它將生成自動更新。我回顧了this tutorial並且也一直在審查GNU make手冊。看起來make是生成我的.d文件但不讀取它們,或者它讀取它們,但由於某些原因不會使用它們。自動生成自動生成的.d文件,但不讀取它們

我的項目是擺好了這些目錄:

  • Src在.cpp文件
  • 包括.HPP文件
  • makedeps的.d文件
  • 對象爲.o文件
  • bin爲最終的可執行文件

這是我的makefile:

BIN=bin 
SRC=src 
INC=include 
DEP=makedeps 
OBJ=objects 
# sources are like 'src/main.cpp' 
sources=$(wildcard $(SRC)/*.cpp) 
# objects are like 'objects/main.o' 
objects=$(subst $(SRC),$(OBJ),$(sources:.cpp=.o)) 
# dependencies are like 'makedeps/main.d' 
deps=$(subst $(SRC),$(DEP),$(sources:.cpp=.d)) 
GPP=g++ 
CPPFLAGS=-std=c++11 
LINKARGS=-L/usr/lib/x86_64-linux-gnu 

# used by the implicit rules that the dependency files use: 
CXX=$(GPP) 

$(BIN)/app.exe : $(objects) 
    $(GPP) $(CPPFLAGS) $(LINKARGS) $(objects) -lcurl -o $(BIN)/app.exe 

# on the first pass this should fail, but it should discover how 
# to build these dependencies and then build them and load them in. 
# once they are loaded in, it should know how to build the object files. 
-include $(deps) 

# this produces the dependency files, the sed command puts directory prefixes 
# before the files 
$(DEP)/%.d : $(SRC)/%.cpp 
    @set -e; rm -f [email protected]; \ 
    $(GPP) -I$(INC) -MM $(CPPFLAGS) $< > [email protected]$$$$; \ 
    sed 's,\($*\)\.o[ :]*,$(OBJ)/\1.o : ,g' < [email protected]$$$$ > [email protected]; \ 
    rm -f [email protected]$$$$ 

.PHONY:clean 
clean: 
    rm -f $(OBJ)/*.o 
    rm -f $(DEP)/*.d 
    rm -f $(BIN)/* 

當我運行make時,它產生的所有相關文件的「makedeps」目錄下,這裏是他們的級聯輸出:

objects/DownloadBuffer.o : src/DownloadBuffer.cpp include/DownloadBuffer.hpp 
objects/Downloader.o : src/Downloader.cpp include/Downloader.hpp \ 
include/DownloadBuffer.hpp 
objects/main.o : src/main.cpp include/Downloader.hpp 

我發現這在GNU就隱含規則手冊文檔:

編譯的C++程序:n.o自動從n.ccn.cpp,或n.C與窗體'的配方製成$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c'

這就是爲什麼我在上面設置CXX = $(GPP)的原因。

但是,沒有生成目標文件。這裏是make輸出:

[email protected]:~/NetBeansProjects/CppApplication_1$ make -f mk.mk clean 
rm -f objects/*.o 
rm -f makedeps/*.d 
rm -f bin/* 
[email protected]:~/NetBeansProjects/CppApplication_1$ make -f mk.mk 
g++ -std=c++11 -L/usr/lib/x86_64-linux-gnu objects/DownloadBuffer.o objects/Downloader.o objects/main.o -lcurl -o bin/app.exe 
g++: error: objects/DownloadBuffer.o: No such file or directory 
g++: error: objects/Downloader.o: No such file or directory 
g++: error: objects/main.o: No such file or directory 
make: *** [bin/app.exe] Error 1 

請注意,.d文件被首先刪除,並且我確認它們是在運行時創建的。在仔細閱讀this section on include directives之後,我有這樣的印象:make應該再次嘗試在創建完成後包含這些.d文件。

有人請解釋爲什麼不生成目標文件?

回答

2

你不能靠潛規則,如果你的目標有一個路徑分隔符,由於方式隱含規則的查找工作,最直接的方式來解決你的問題是後$(BIN)/app.exe

$(objects): 
    $(GPP) $(CPPFLAGS) $(CXXFLAGS) -c $^ -o [email protected] 

,以提供一個明確的食譜他說,GCC在一段時間內擁有更好的依賴關係生成,但看起來文檔還沒有趕上。您可以使用-MMD生成依賴關係作爲編譯的副作用,這意味着您可以除去所有sed crud(-MP爲標題添加虛擬目標,以避免在刪除它們時出現問題)。

你的Makefile應該是這個樣子

BIN := bin 
SRC := src 
INC := include 
OBJ := objects 

app  := $(BIN)/app.exe 
sources := $(wildcard $(SRC)/*.cpp) 
objects := $(subst $(SRC),$(OBJ),$(sources:.cpp=.o)) 
deps := $(objects:.o=.d) 

CXX  := g++ 
CPPFLAGS := -I $(INC) -MMD -MP 
CXXFLAGS := -std=c++11 
LDFLAGS := -L /usr/lib/x86_64-linux-gnu 
LDLIBS := -lcurl 

$(app) : $(objects) 
    $(CXX) $(LDFLAGS) $^ $(LDLIBS) -o [email protected] 

$(OBJ)/%.o: $(SRC)/%.cpp 
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $^ -o [email protected] 

.PHONY: clean 
clean: ; $(RM) $(objects) $(deps) $(app) 

-include $(deps) 

其他一些注意事項,你可從文件

  • 使用:=而不是=看,除非你有一個需要爲後者
  • 如果您的標題位於單獨的文件夾中,則需要添加路徑
  • 在sa中輸出依賴關係我的目錄作爲你的對象更簡單的時候使用GCC的自動依賴生成器。如有必要,您可以使用-MF更改輸出文件。
  • 鏈接時不需要提供CPPFLAGS,它不執行任何預處理。
  • 您應該堅持使用默認鏈接器配方&變量(和CXX)。
  • 儘可能在食譜中使用自動變量([email protected]等)。

如果您真的想要使用隱式規則,您需要執行一些操作,例如從目標文件中刪除路徑並事先更改爲對象目錄。

+0

我很困惑,你說我應該有一個明確的配方來創建我的目標文件,但是.d文件應該創建這個配方,冗餘規則不會相互衝突嗎?我也從來不知道CPPFLAGS只是用於預處理(我認爲你的意思是編譯對不對?)。我用它來保存-std = C++ 11,從你的解決方案來看,我猜連接器不需要知道標準。 – msknapp 2014-09-23 00:59:56

+0

所以我認爲make會爲同一個目標合併單獨的規則,我是否正確解釋? – msknapp 2014-09-23 01:08:55

+0

OMG它的工作!我不必改變一件事!我認爲這是我見過的最美麗的製作文件,非常感謝。 – msknapp 2014-09-23 01:24:23