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

时间:2010-09-15 01:18:35

标签: c++ c makefile dependencies gnu-make

这是我当前的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'会重新生成依赖文件。我怎么能避免这个?对于这个人为的例子来说,这不是什么大问题,但对于一个大型项目来说,这可能非常耗时。

感谢。

4 个答案:

答案 0 :(得分:23)

这是因为.d文件无条件地-include d。就make所知,他们可以向clean目标添加依赖项或命令。出于这个原因,首先构建所有include d文件,否则可能会出现错误或失败的构建。要禁用此功能,您需要有条件地包含依赖项文件:

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

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

%.d:
    @touch $@

最初创建依赖项文件。

答案 1 :(得分:5)

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

MAKEFILE_TARGETS_WITHOUT_INCLUDE := clean distclean doc

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

答案 2 :(得分:4)

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

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

答案 3 :(得分:2)

-中的前导-include表示make 不会抱怨如果依赖项丢失且无法重新制作,但它不会' t意味着它不会首先尝试使它们(并且,在这种情况下,成功) - 毕竟,任何有趣或重要的都可以包含在所包含的文件中,让我们尝试让他们尝试。我认为没有办法阻止它。

有关include-include的文档,请参阅here