使用-MM生成include指令和依赖项生成

时间:2010-05-10 09:18:31

标签: c++ g++ makefile

如果包含的目标已过期或不存在,我希望构建规则由include指令触发。

目前makefile看起来像这样:

program_NAME := wget++
program_H_SRCS := $(wildcard *.h)
program_CXX_SRCS := $(wildcard *.cpp)
program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
program_OBJS := $(program_CXX_OBJS)

DEPS = make.deps

.PHONY: all clean distclean

all: $(program_NAME) $(DEPS)

$(program_NAME): $(program_OBJS)
    $(LINK.cc) $(program_OBJS) -o $(program_NAME)

clean:
    @- $(RM) $(program_NAME)
    @- $(RM) $(program_OBJS)
    @- $(RM) make.deps

distclean: clean

make.deps: $(program_CXX_SRCS) $(program_H_SRCS)
    $(CXX) $(CPPFLAGS) -MM $(program_CXX_SRCS) > make.deps

include $(DEPS)

问题在于,似乎include规则在构建make.deps的规则之前执行,这实际上意味着如果make.deps不存在或者始终从make.deps获取make,则要么不获取依赖关系列表上一个版本,而不是当前版本。

例如:

$ make clean 
$ make
makefile:32: make.deps: No such file or directory
g++  -MM addrCache.cpp connCache.cpp httpClient.cpp wget++.cpp > make.deps
g++    -c -o addrCache.o addrCache.cpp
g++    -c -o connCache.o connCache.cpp
g++    -c -o httpClient.o httpClient.cpp
g++    -c -o wget++.o wget++.cpp
g++      addrCache.o connCache.o httpClient.o wget++.o -o wget++

修改

我读了docs for the include directive,听起来如果包含目标不存在,它将继续处理父makefile尝试并构建目标,但我不完全清楚这是如何工作的:

  

如果包含的makefile不能   在任何这些目录中找到,a   生成警告消息,但它   不是一个立即致命的错误;   处理包含的makefile   包括继续。一旦它有了   完成阅读makefile,make will   尝试重新制作任何过时的东西   或者不存在。见节如何   Makefile是重制的。只有在它之后   我试图找到一种方法来重拍   makefile和失败,将使   将缺少的makefile诊断为   致命的错误。

ANSWER

这是我接受的答案的修改。缺少的一件事是依赖文件也依赖于源,并且除非将它们添加到包含的deps文件中,否则不会重新生成:

%.d: $(program_CXX_SRCS)
    @ $(CXX) $(CPPFLAGS) -MM $*.cpp | sed -e 's@^\(.*\)\.o:@\1.d \1.o:@' > $@

sed.d文件的名称添加到每个依赖关系行的开头,如下所示:

foo.d foo.o: foo.cpp foo.h bar.h baz.h

我从这篇关于递归制作的危险的惊人论文中得到了这个想法:

Recursive Make Considered Harmful

我还将以下内容添加到makefile中:

clean_list += ${program_SRCS:.c=.d}

# At the end of the makefile
# Include the list of dependancies generated for each object file
# unless make was called with target clean
ifneq "$(MAKECMDGOALS)" "clean"
-include ${program_SRCS:.c=.d}
endif

3 个答案:

答案 0 :(得分:2)

您依靠隐式规则来编译.cpp文件。您必须重新定义它以使用将创建依赖项文件的-MM和-MF标志。

%.o: %.cpp
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ -MM -MF $@.d

然后,您必须使用-include在Makefile中包含这些依赖项文件,这些文件在依赖项文件尚不存在时(第一次或在干净之后)不会出错。

program_DEPS := $(program_OBJS:.o=.o.d)
-include $(program_DEPS)

请记住在clean规则中为依赖项文件添加rm命令。

答案 1 :(得分:2)

我花了一段时间才掌握的重点是上一版本的make.deps足够好。考虑一下:对于给定的目标文件,依赖项文件列表可以更改的唯一方法是...是否已更改其中一个旧的依赖项文件。如果是这种情况,那么旧的make.deps将导致重建该目标文件,如果重建目标文件也重建make.deps,那么一切都将是最新的。 在检查哪些对象必须重建之前,您不必重建make.deps。

答案 2 :(得分:0)

include指令的工作方式与它们在C和C ++中的工作方式相同 - 它们在发生任何其他事件之前进行处理,以构建生成然后进程的“真实”makefile。具体来说,它们在任何规则被触发之前被处理。