制造问题
Issue with make
让我们考虑这个小例子。没有 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 ...)。其实我期待这样的错误:"Unable to find VILLAIN to make obj/foo.o"
生成文件:
#!/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%)
为什么要在构建先决条件之前尝试创建目标?
在这方面,模式规则不像显式规则那样起作用。可以有许多不同的模式规则可用于创建相同的目标(考虑,.o
可以从 C 源文件、C++ 源文件、FORTRAN 源文件等创建)
因此,当 make 尝试找到构建目标的模式规则时,为了确定模式是否匹配,make 将尝试构建所有先决条件。如果无法构建先决条件之一,那么这不是错误! Make 只是继续匹配并尝试下一个模式规则。所以 VILLIAN
不存在且无法构建这一事实,仅意味着 make 永远不会 select 此模式规则,因为无法满足先决条件......但这不是错误并且不会打印任何消息(好吧,如果您查看 make 的调试输出,您会看到有关它的注释)。
所以 make 会发现它没有知道如何构建的规则 obj/foo.o
。你会期望在那个时候得到一个错误......但你不会因为你已经添加了这个规则:
$(OBJ) : | $(OBJDIR)
通过这样做,您已将 obj/foo.o
声明为 make 知道的目标,因此如果目标不存在,它不会抱怨。如果您更改此设置以将 order-only 先决条件添加到模式规则中,那么您将获得更易于理解的行为:
$(OBJDIR)/%.o: $(SRCDIR)/%.c VILLAIN | $(OBJDIR)
cp $< $@
$(OBJDIR):
mkdir -p $@
给出:
make: *** No rule to make target 'obj/foo.o', needed by 'out.exe'. Stop.
让我们考虑这个小例子。没有 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 ...)。其实我期待这样的错误:"Unable to find VILLAIN to make obj/foo.o"
生成文件:
#!/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%)
为什么要在构建先决条件之前尝试创建目标?
在这方面,模式规则不像显式规则那样起作用。可以有许多不同的模式规则可用于创建相同的目标(考虑,.o
可以从 C 源文件、C++ 源文件、FORTRAN 源文件等创建)
因此,当 make 尝试找到构建目标的模式规则时,为了确定模式是否匹配,make 将尝试构建所有先决条件。如果无法构建先决条件之一,那么这不是错误! Make 只是继续匹配并尝试下一个模式规则。所以 VILLIAN
不存在且无法构建这一事实,仅意味着 make 永远不会 select 此模式规则,因为无法满足先决条件......但这不是错误并且不会打印任何消息(好吧,如果您查看 make 的调试输出,您会看到有关它的注释)。
所以 make 会发现它没有知道如何构建的规则 obj/foo.o
。你会期望在那个时候得到一个错误......但你不会因为你已经添加了这个规则:
$(OBJ) : | $(OBJDIR)
通过这样做,您已将 obj/foo.o
声明为 make 知道的目标,因此如果目标不存在,它不会抱怨。如果您更改此设置以将 order-only 先决条件添加到模式规则中,那么您将获得更易于理解的行为:
$(OBJDIR)/%.o: $(SRCDIR)/%.c VILLAIN | $(OBJDIR)
cp $< $@
$(OBJDIR):
mkdir -p $@
给出:
make: *** No rule to make target 'obj/foo.o', needed by 'out.exe'. Stop.