让我们考虑一下这个小例子。没有VILLAIN
,一切都应该可以正常工作。实际上这个词会导致错误但不是我期待它的地方......
错误:
$ make
mkdir -p obj
zip out.exe obj/foo.o obj/bar.o obj/baz.o
zip warning: name not matched: obj/foo.o
zip warning: name not matched: obj/bar.o
zip warning: name not matched: obj/baz.o
zip error: Nothing to do! (out.exe)
Makefile:9: recipe for target 'out.exe' failed
make: *** [out.exe] Error 12
似乎make想通过执行尚未生成依赖关系的配方(obj / foo.o ...)来加快速度。实际上我期待的错误如下:"无法找到VILLAIN来制作obj / foo.o"
Makefile:
#!/usr/bin/env make
SRCDIR = src
OBJDIR = obj
SRC = $(addsuffix .c,foo bar baz)
OBJ = $(addprefix $(OBJDIR)/, $(notdir $(SRC:c=o)))
out.exe: $(OBJ)
zip $@ $^
$(OBJDIR)/%.o: $(SRCDIR)/%.c VILLAIN
cp $< $@
$(OBJ) : | $(OBJDIR)
$(OBJDIR):
mkdir -p $@
clean:
rm -f *.c
rm -rf $(OBJDIR)/ $(SRCDIR)/
mkdir -p $(SRCDIR)/
touch $(addprefix $(SRCDIR)/,$(SRC))
但是,如果我删除恶棍,一切正常:
$ make clean
rm -f *.c
rm -rf obj/ src/
mkdir -p src/
touch src/foo.c src/bar.c src/baz.c
$ make
mkdir -p obj
cp src/foo.c obj/foo.o
cp src/bar.c obj/bar.o
cp src/baz.c obj/baz.o
zip out.exe obj/foo.o obj/bar.o obj/baz.o
adding: obj/foo.o (stored 0%)
adding: obj/bar.o (stored 0%)
adding: obj/baz.o (stored 0%)
为什么在构建其先决条件之前尝试制作目标?
答案 0 :(得分:2)
在这方面,模式规则不像显式规则那样工作。可以使用许多不同的模式规则来创建相同的目标(考虑,可以从C源文件,C ++源文件,FORTRAN源文件等创建.o
。)< / p>
因此,当make尝试查找模式规则来构建目标时,为了确定模式是否匹配make将尝试构建所有先决条件。如果无法构建其中一个先决条件,则它不是错误!简单地继续下一个匹配并尝试该模式的模式规则。因此VILLIAN
不存在且无法构建的事实,只是意味着make永远不会选择此模式规则,因为前提条件无法满足......但这不是错误,也不会有任何消息打印(好吧,如果你看看make的调试输出,你会看到一个关于它的注释)。
因此make会发现它没有规则知道如何构建obj/foo.o
。你希望在那时得到一个错误...但是你不会因为你已经添加了这个规则:
$(OBJ) : | $(OBJDIR)
通过这样做,你已经宣布obj/foo.o
是一个让人知道的目标,所以如果目标不存在,它就不会抱怨。如果您更改此选项以将仅订单的先决条件添加到模式规则中,那么您将获得更易于理解的行为:
$(OBJDIR)/%.o: $(SRCDIR)/%.c VILLAIN | $(OBJDIR)
cp $< $@
$(OBJDIR):
mkdir -p $@
给出:
make: *** No rule to make target 'obj/foo.o', needed by 'out.exe'. Stop.