为什么这个makefile在’make clean’上执行目标

这是我目前的makefile。

CXX = g++ CXXFLAGS = -Wall -O3 LDFLAGS = TARGET = testcpp SRCS = main.cpp object.cpp foo.cpp OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) .PHONY: clean all all: $(TARGET) $(TARGET): $(OBJS) $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET) .cpp.o: $(CXX) $(CXXFLAGS) -c $< -o $@ %.d: %.cpp $(CXX) -M $(CXXFLAGS) $ $@ clean: rm -f $(OBJS) $(DEPS) $(TARGET) -include $(DEPS) 

它完美地运行一个例外。 如果目录已经是干净的(没有* .d,* .o)并且我运行’make clean’,它会重新创建依赖项,然后立即删除它们:

 [user@server proj]$ make g++ -M -Wall -O3 foo.cpp > foo.d g++ -M -Wall -O3 object.cpp > object.d g++ -M -Wall -O3 main.cpp > main.d g++ -Wall -O3 -c main.cpp -o main.o g++ -Wall -O3 -c object.cpp -o object.o g++ -Wall -O3 -c foo.cpp -o foo.o g++ -Wall -O3 main.o object.o foo.o -o testcpp [user@server proj]$ make clean rm -f main.o object.o foo.o main.d object.d foo.d testcpp [user@server proj]$ make clean g++ -M -Wall -O3 foo.cpp > foo.d g++ -M -Wall -O3 object.cpp > object.d g++ -M -Wall -O3 main.cpp > main.d rm -f main.o object.o foo.o main.d object.d foo.d testcpp [user@server proj]$ 

我不明白为什么第二个’make clean’会重新生成依赖文件。 我怎么能避免这个? 对于这个人为的例子来说,这不是什么大问题,但对于一个大型项目来说,这可能非常耗时。

谢谢。

这是因为.d文件无条件地包含-include 。 据make知道,他们可以向clean目标添加依赖项或命令。 由于这个原因,首先构建所有include d文件,否则您可能会得到不正确或失败的构建。 要禁用此function,您需要有条件地包含依赖项文件:

 ifneq ($(MAKECMDGOALS),clean) -include $(DEPS) endif 

另一种解决方案是使用touch生成依赖文件,并将它们替换为实际数据作为编译的副作用。 这就是automake进行依赖关系跟踪的方式,因为它可以使一次性构建更快。 如果你想走这条路线,请查看gcc-MD-MMD选项。 使用模式规则,如:

 %.d: @touch $@ 

最初创建依赖项文件。

它想要重新生成依赖项文件,因为它总是尝试在执行任何其他操作之前重新生成所有的makefile,包括-include’dmafiles。 (嗯,实际上,对我而言,它没有那样做 – 我有GNU Make 3.81 – 所以也许这是你的版本中的一个错误已被修复,或者是我的优化,而你的优化不是。但无论如何。)

最简单的方法是编写规则,使它们生成.d文件作为常规编译的副作用,而不是生成明确的规则来生成它们。 这样,当他们不在那里时,Make不知道如何生成它们所以它不会尝试(在干净的树中,.cpp.o规则就足够了,你不需要头文件依赖项) 。 查看一个Automake生成的makefile – 一个简单的makefile – 看看它是如何完成的。

如果要跳过多个目标的包含,可以使用filterfunction。

 MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean distclean doc # Include only if the goal needs it ifeq ($(filter $(MAKECMDGOALS),$(MAKEFILE_TARGETS_WITHOUT_INCLUDE)),) -include $(DEPS) endif 

引导-意味着如果依赖项缺失且不能重新制作, make 将不会抱怨 ,但这并不意味着它不会首先尝试制作它们 (并且,在这种情况下,成功) – – 毕竟,任何有趣或重要的东西都可能出现在所包含的文件中,从而让我们尝试让它们尝试。 我认为没有办法阻止这种情况。

有关include-include文档,请参阅此处 。