2014-09-22 82 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