自动生成自动生成的.d文件,但不读取它们
问题描述:
我想为我的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.cc
,n.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文件。
有人请解释为什么不生成目标文件?
答
你不能靠潜规则,如果你的目标有一个路径分隔符,由于方式隐含规则的查找工作,最直接的方式来解决你的问题是后$(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]
等)。
如果您真的想要使用隐式规则,您需要执行一些操作,例如从目标文件中删除路径并事先更改为对象目录。
我很困惑,你说我应该有一个明确的配方来创建我的目标文件,但是.d文件应该创建这个配方,冗余规则不会相互冲突吗?我也从来不知道CPPFLAGS只是用于预处理(我认为你的意思是编译对不对?)。我用它来保存-std = C++ 11,从你的解决方案来看,我猜连接器不需要知道标准。 – msknapp 2014-09-23 00:59:56
所以我认为make会为同一个目标合并单独的规则,我是否正确解释? – msknapp 2014-09-23 01:08:55
OMG它的工作!我不必改变一件事!我认为这是我见过的最美丽的制作文件,非常感谢。 – msknapp 2014-09-23 01:24:23