有什么方法可以将多个目标作为一系列单个 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 函数中。
我有以下 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 函数中。