有什么方法可以将多个目标作为一系列单个 make 调用吗?

Is there any way to make multiple targets as series of single make invocations?

我有以下 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 完全按照你告诉它做的去做,而你没有告诉 us 你想让它做什么,这与你告诉它做的不同(说修复此类不正确的行为 如果您不定义行为的不正确之处,则对我们没有真正的帮助),因此我们帮不了您太多。

您可能对包含的 makefile 和比较 $(MAKECMDGOALS) 之间的交互感到困惑。请注意:

ifneq ($(MAKECMDGOALS),clean)

除非您指定一个目标,否则不会匹配:clean。在您指定多个目标的情况下,其中一个是干净的,它将匹配,因为 clean all 不等于 clean。因此,当您 运行 make clean all make 时,将 包含生成的 makefile,如果它不存在,则会生成它。

因为生成的包含文件只重建一次,所以当 makefile 第一次被解析时,不可能这样说:"first run rule X (e.g., clean) then rebuild the included makefiles, then reinvoke make".

然而,用 clean all 调用 make 几乎总是一个坏主意。这是因为如果您曾经尝试添加 -j 以实现并行性,则清理和构建将 运行 并行并破坏所有内容。

一个半常见的选项是提供一个不同的规则来同时执行这两种操作,如下所示:

rebuild:
        $(MAKE) clean
        $(MAKE) all

然后运行改为make rebuild

您当然可以在 shell 的帮助下强制执行此行为。例如,在 bash 中,您可以使用

for target in "clean" "all";
do
   make $target;
done

如果您打算多次重做该过程,您可以将其设为可执行脚本或将其包装在 shell 函数中。