我知道以下makefile会让预处理器自动生成依赖项(在.d文件中)并将它们包含在makefile中(因为我的课程说明是这样说的),这样它们就不必自动维护了。 -MMD
标志是对此负责的。我没有得到的是:.d文件在什么时候生成?甚至没有任何使用${CXXFLAGS}
的命令。据推测,像${CXX} ${CXXFLAGS} -c x.C -o x.o
这样的命令将由每个目标文件的make自动推导出来,但如果这些是生成.d文件的命令,我们是不是已经通过知道xo的依赖关系的点了如果我们只通过执行生成这些.o文件的命令来了解它们,那么yo和zo可能是相关的吗? (假设有一些.h文件,如果留下来自行推断规则,makefile会忽略。)
CXX = g++ # compiler
CXXFLAGS = -g -Wall -MMD # compiler flags
OBJECTS = x.o y.o z.o # object files forming executable
DEPENDS = ${OBJECTS:.o=.d} # substitutes ".o" with ".d"
EXEC = a.out # executable name
${EXEC} : ${OBJECTS} # link step
${CXX} ${OBJECTS} -o ${EXEC}
-include ${DEPENDS} # copies files x.d, y.d, z.d (if they exist)
答案 0 :(得分:11)
据推测,像
${CXX} ${CXXFLAGS} -c x.C -o x.o
这样的命令将由每个目标文件的make自动推导出来,但如果这些是生成.d文件的命令,我们就不会已经知道了xo,yo和zo的依赖关系可能是相关的,如果我们只通过执行生成这些.o文件的命令来了解它们吗?
你在这里是对的。第一次运行Makefile时,依赖项不存在。
但这没关系 - 仅当.o文件已存在且您已更改.h文件时才需要依赖性信息。第一次运行Make时,无论如何都需要构建所有.o文件,并且同时生成.d文件。
之后,.d文件将提供依赖性信息。如果更改了标头,则依赖关系信息将告知Make哪些.o文件需要重建。如果更改了源文件,则始终需要重建.o,并且将同时生成更新的相关性信息。
答案 1 :(得分:2)
如果你想知道你背后的makefile做了什么,请使用-p标志,并将输出重定向到一个文件,因为它有很多东西。
make -p foo > bar
将转储make foo
的所有变量值和规则,然后查看bar
将显示为隐式规则运行的命令。在您的情况下,它会向您显示.cpp.o
或%.o: %.cpp
(奇怪的是他们都在那里)规则将调用$(COMPILE.cpp)
,其解析为$(COMPILE.cc)
,其解析为{{ 1}}。哪个有趣的属性,你可以添加到CXXFLAGS或CPPFLAGS以使它们进入你的.cpp.o编译,但不是CFLAGS,它仅由$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
规则使用,这有点意义,因为你可能希望您的C文件和C ++文件处理方式不同(CC和CXX通常也设置为不同的编译器)。
答案 2 :(得分:0)
是的,你是对的,如果你删除了依赖文件,但保留了目标文件,那么make将运行不完整的依赖信息,并且可能无法重新构建其标题已更改的目标文件。 / p>
Make也可能拒绝构建 - 当依赖文件引用您已删除的标头(显然不再引用任何其他来源)时会发生这种情况。由于Make不知道如何在编译之前重建依赖项文件,它所能做的就是报告缺少的依赖项(然后明显的操作是删除依赖项文件,导致上面的第一个条件)。
唯一的答案是纪律:删除依赖项文件时,始终删除目标文件。您可以使用clean
目标来帮助解决此问题。
clean::
$(RM) *.o *.d
或者另外,告诉Make如何创建依赖文件:
%.dep: %.cc
$(CXX) -MM $(CPPFLAGS) $< | sed -e 's,\($*\)\.o[ :]*,\1.o $@: ,g' > $@
(sed
命令确保依赖项本身依赖于与目标文件相同的源。)