有没有办法将多个目标作为一系列的单个调用?



我有以下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 allmake将包含生成的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函数中。

最新更新