我有以下Makefile
:
ifneq ($(MAKECMDGOALS),clean)
-include generated.mk
endif
FOO ?= foo
all: a.txt
a.txt:
echo $(GEN_FOO) > $@
generated.mk: Makefile
echo GEN_FOO = $(FOO) > $@
.PHONY: clean
clean:
$(RM) a.txt
$(RM) generated.mk
构建单个目标时工作正常:
$ make clean
rm -f a.txt
rm -f generated.mk
$ make all
echo GEN_FOO = foo > generated.mk
echo foo > a.txt
但是,当我尝试一次构建多个目标时,事情就不那么顺利了:
$ make clean all
rm -f a.txt
rm -f generated.mk
echo foo > a.txt
$ make all
echo GEN_FOO = foo > generated.mk
make: Nothing to be done for 'all'.
如果提供变量,情况会变得更糟:
$ make clean
rm -f a.txt
rm -f generated.mk
$ make FOO=bar clean all
echo GEN_FOO = bar > generated.mk
rm -f a.txt
rm -f generated.mk
echo bar > a.txt
$ make all
echo GEN_FOO = foo > generated.mk
make: Nothing to be done for 'all'.
$ make FOO=bar clean all
rm -f a.txt
rm -f generated.mk
echo foo > a.txt
有没有办法解决这种不正确的行为?
Make 完全按照你告诉它做的事情去做,你还没有告诉我们你想要它做什么,这与你告诉它做的事情不同(当你不定义行为的错误时,说修复这种不正确的行为并没有真正帮助我们(,所以我们不能帮你很多。
您可能会对包含的生成文件和比较$(MAKECMDGOALS)
之间的交互感到困惑。 请注意:
ifneq ($(MAKECMDGOALS),clean)
除非您只指定一个目标,否则这将不匹配:clean
。 在指定多个目标(其中一个是干净的(的情况下,该目标将匹配,因为clean all
不等于clean
。 因此,当您运行时make clean all
make将包含生成的makefile,如果它不存在,则会生成它。
由于生成的包含文件仅重建一次,因此在首次解析 makefile 时,不可能说:"首先运行规则 X(例如,clean
(,然后重建包含的 makefile,然后重新调用 make"。
但是,用clean all
调用 make 几乎总是一个坏主意。 这是因为如果你试图为并行性添加-j
,干净和构建将并行运行并破坏一切。
一个半常见的选项是提供一个不同的规则来同时执行这两项操作,如下所示:
rebuild:
$(MAKE) clean
$(MAKE) all
然后改为运行make rebuild
。
您当然可以在 shell 的帮助下强制行为。例如,在bash
您可以使用
for target in "clean" "all";
do
make $target;
done
如果你要重新做这个过程很多,你可以把它变成一个可执行脚本,或者把它包装在一个shell函数中。