有没有一种方法可以在shell
函数中使用导出的变量而不需要sub-make?
以下面的例子为例。
FOO := BAR
.EXPORT_ALL_VARIABLES:
.PHONY: buzz
buzz:
$(info buzz)
$(error finish)
.PHONY: fizz
fizz: $(if $(shell echo $$FOO),buzz,)
$(info fizz)
$(MAKE) fizz
如果我像这样运行fizz
目标,我会得到以下输出。
$ make fizz
fizz
make fizz
make[1]: Entering directory '/home/jshbrntt/test'
buzz
Makefile:8: *** finish. Stop.
make[1]: Leaving directory '/home/jshbrntt/test'
make: *** [Makefile:13: fizz] Error 2
正如您所看到的,只有make fizz
的第二次运行扩展了shell
函数,并导致buzz
目标也运行。
有没有一种方法可以在不需要sub-make的情况下使用
shell
函数中的导出变量?
否
请始终记住,GNUmake
函数(如$(shell)
(是在解析生成文件时评估的,而不是在make
运行配方时(请参阅手册第3.7节(,无论$(shell)
调用出现在生成文件的何处。make
根据其自身的环境以及makefile中所有规则和export
/unexport
指令的组合来确定导出哪些变量,可能包括通过$(shell)
和其他函数生成的规则和/或指令。通过这种方式,它确保了用于执行配方的环境的一致性。
虽然可以想象make
会将其导出列表的中间形式暴露给$(shell)
函数(其文档中没有明确说明它是否这样做(,但实际上,它这样做会令人惊讶,而且你的实验表明它没有这样做。尽管手册没有明确地直接谈到这个问题,应注意的是其export
、等的文档。在标题为将变量通信到子make
的部分中。
就我个人而言,我建议完全避免使用$(shell)
(和$(wildcard)
(。如果你确实使用$(shell)
,那么我建议将其保留给外部食谱使用。在食谱中,直接使用shell代码。这一点更清楚,当然是在makefile语义(何时评估(方面,但通常也是在实际代码方面。对于您的特定示例,可能看起来是这样的:
FOO := BAR
.EXPORT_ALL_VARIABLES:
.PHONY: fizz
fizz:
@echo fizz
@if test -n "$$FOO"; then echo FOO found; else echo FOO missing; make fizz; fi
在GNU make的所有当前版本中,导出的变量不会发送到shell
函数。可能会发生一些非常恶劣的递归行为(如果你写export BAR = $(shell echo $$FOO)
呢??(
在GNU make的下一个版本中,make变量将导出到shell
函数。
然而,在配方中使用shell
从来没有任何好的理由。配方是在shell中运行的,因此您可以直接编写所需的命令。因此,如果你的例子是准确的,你想在配方中使用这个工具,只需去掉shell
调用:
.PHONY: fizz
fizz:
@echo fizz
@test -n $$FOO && echo FOO found || echo FOO missing