访问shell函数中导出的变量



有没有一种方法可以在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

最新更新