如果包含的目标已过期或不存在,我希望包含指令触发构建规则。
目前 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 要么获取不到依赖项列表,要么总是获取make.deps 来自上一版本,而不是当前版本。
例如:
$ 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++
编辑
我阅读了 包含的文档指令,听起来如果包含目标不存在,它将继续处理父 makefile 尝试并构建目标,但我并不完全清楚这是如何工作的:
如果包含的 makefile 不能
在这些目录中的任何一个中都可以找到
生成警告消息,但它
不是立即致命的错误;
处理包含以下内容的 makefile
包括继续。一旦有了
读完makefile后,make将会
尝试重制任何过时的内容
或者不存在。请参阅“如何”部分
Makefile 被重新制作。只有在它之后
试图找到一种方法来重新制作
makefile 失败,将 make
将丢失的 makefile 诊断为
致命错误。
答案
这是对我接受的答案的修改。缺少的一件事是依赖文件也依赖于源,并且不会重新生成,除非将它们添加到所包含的 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
我从这篇关于递归 make 危险的精彩论文中得到了这个想法:
递归 Make 被认为有害
我还将以下内容添加到 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
I want a build rule to be triggered by an include directive if the target of the include is out of date or doesn't exist.
Currently the makefile looks like this:
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)
The problem is that it seems like the include directive is executing before the rule to build make.deps which effectively means that make is either getting no dependency list if make.deps doesn't exist or always getting the make.deps from the previous build and not the current one.
For example:
$ 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++
Edit
I read the docs for the include directive, and it sounds like if the include target doesn't exist it will continue processing the parent makefile try and build the target, but it's not completely clear to me how this works:
If an included makefile cannot be
found in any of these directories, a
warning message is generated, but it
is not an immediately fatal error;
processing of the makefile containing
the include continues. Once it has
finished reading makefiles, make will
try to remake any that are out of date
or don't exist. See section How
Makefiles Are Remade. Only after it
has tried to find a way to remake a
makefile and failed, will make
diagnose the missing makefile as a
fatal error.
ANSWER
This is a modification of the answer I accepted. The one thing missing was that the dependency files also depend on the sources, and won't get regenerated unless they are added to the deps files which are being included:
%.d: $(program_CXX_SRCS)
@ $(CXX) $(CPPFLAGS) -MM $*.cpp | sed -e 's@^\(.*\)\.o:@\1.d \1.o:@' > $@
sed
adds the name of the .d
file to the beginning of each dependency line like so:
foo.d foo.o: foo.cpp foo.h bar.h baz.h
I got the idea from this amazing paper on the dangers of recursive make:
Recursive Make Considered Harmful
I also add the following to the 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)
我花了一段时间才理解的一个重要点是之前构建的 make.deps 足够好。想一想:对于给定的目标文件,依赖文件列表可以更改的唯一方法是...旧的依赖文件之一已被更改。如果是这种情况,那么旧的 make.deps 将导致该目标文件被重建,并且如果重建目标文件也重建 make.deps,那么一切都将是最新的。 在检查哪些对象必须重建之前,您不必重建 make.deps。
An important point that it took me a while to grasp is that the make.deps from the previous build are good enough. Think about it: for a given object file, the only way the list of dependency files can change is if... one of the old dependency files has been altered. And if that's the case, then the old make.deps will cause that object file to be rebuilt, and if rebuilding the object file also rebuilds make.deps, then everything will be up to date. You don't have to rebuild make.deps before checking to see which objects must be rebuilt.
您依赖隐式规则来编译 .cpp 文件。您必须重新定义它以使用将创建依赖项文件的 -MM 和 -MF 标志。
然后,您必须使用
-include
将这些依赖项文件包含在 Makefile 中,当依赖项文件尚不存在(第一次或清理后)时,不会出现错误。并记住在 clean 规则中添加依赖文件的 rm 命令。
You are relying on an implicit rule to compile your .cpp files. You have to redefine it to use the -MM and -MF flags that will create the dependency file.
Then, you have to include these dependencies files in the Makefile, using
-include
that will not error when the dependencies files do not exist yet (on the first time, or after a clean).And remember to add the rm command for the dependencies files in the clean rule.
include 指令的工作方式与 C 和 C++ 中的工作方式类似 - 它们在其他任何事情发生之前进行处理,以构建 make 然后处理的“真正的”makefile。具体来说,它们是在触发任何规则之前进行处理的。
The include directives work like they do in C and C++ - they are processed before anything else happens, to build the "real" makefile that make then processes. Specifically, they are processed before any rules are fired.