Makefile 如何声明只计算一次的延迟变量?

Makefile 如何声明只计算一次的延迟变量?,makefile,gnu-make,Makefile,Gnu Make,我有一个shell程序,需要很长时间才能完成。如前所述,执行make build需要4 x 2秒才能完成,因为$(值)是为每个文件计算的 一种解决方案是通过使用:=而不是=来声明值一个延迟的变量 不幸的是,这也不是一个解决方案,因为它会将makeclean和任何其他目标的执行速度降低2秒,因为值是免费计算的 value = $(shell sleep 2 && echo 42) in = a b c d out = $(addsuffix .out,$(in)) build:

我有一个shell程序,需要很长时间才能完成。如前所述,执行
make build
需要4 x 2秒才能完成,因为
$(值)
是为每个文件计算的

一种解决方案是通过使用
:=
而不是
=
来声明
一个
延迟的
变量

不幸的是,这也不是一个解决方案,因为它会将
makeclean
和任何其他目标的执行速度降低2秒,因为
是免费计算的

value = $(shell sleep 2 && echo 42)

in = a b c d
out = $(addsuffix .out,$(in))

build: $(out)

%.out: %
    echo $(value) > $< || [ rm $@ -a true ]

init:
    touch $(in)

clean:
    rm -vf $(out)

您可以根据
$(MAKECMDGOALS)
中的目标名称进行分配:


有关详细信息,请参见。

您可以根据
$(MAKECMDGOALS)
中的目标名称进行分配:


有关详细信息,请参见。

一种解决方案是将该值转换为常规文件目标,仅当其先决条件更改时才会更新。如果你坚持在每次构建时都要重建目标,那就把它标记为假的

如果
clean
目标不依赖于该文件,则在调用
makeclean
时不会重建该文件


%.输出:%
echo$(值)>$<| |[rm$@-真值]

echo$(value)>$一种解决方案是将该值转换为常规文件目标,只有在其先决条件更改时才会更新。如果你坚持在每次构建时都要重建目标,那就把它标记为假的

如果
clean
目标不依赖于该文件,则在调用
makeclean
时不会重建该文件


%.输出:%
echo$(值)>$<| |[rm$@-真值]

echo$(value)>$您可以玩一个小把戏:

value = $(eval value := $(shell cat shelve))$(value)
工作原理:
首先使用递归赋值进行赋值,因此RHS上的值不会展开

第一次扩展
时,make解析器将首先运行
$(eval…
,这将启动makefile的“新解析器”。在该解析器中,计算内容
值:=$(cat shelve)
。这里,
是一个简单的变量赋值,因此RHS立即展开,运行
$(shell…
并赋值给

记住make实际上没有变量范围的概念,所以这个
就是我们在外部解析器中设置的同一个全局
变量

然后eval完成并扩展为空字符串,make继续解析内容。在这里它找到值
$(value)
,并展开该值<代码>值
现在具有来自评估的结果,而不是评估文本本身,因此这将被展开

也许这会有帮助:

value = $(eval value := $(shell cat shelve))$(value)
此处
value
包含字符串
$(评估值:=$(shell cat shelve))$(值)

现在展开它:

%.out: %
        echo $(value) > $< ...
首先,它展开了
eval
,解析如下:

value := $(shell cat shelve)
变量设置为简单展开的变量,因此RHS立即展开。假设
cat shelve
的结果为“foo”,因此
value
现在设置为
foo
(并且标记为简单展开)


这是评估的结束,然后make开始下一部分,它是
$(value)
,因此它查找变量
value
,发现它是一个值为
foo

的简单扩展变量。下面是一个可以玩的小把戏:

value = $(eval value := $(shell cat shelve))$(value)
工作原理:
首先使用递归赋值进行赋值,因此RHS上的值不会展开

第一次扩展
时,make解析器将首先运行
$(eval…
,这将启动makefile的“新解析器”。在该解析器中,计算内容
值:=$(cat shelve)
。这里,
是一个简单的变量赋值,因此RHS立即展开,运行
$(shell…
并赋值给

记住make实际上没有变量范围的概念,所以这个
就是我们在外部解析器中设置的同一个全局
变量

然后eval完成并扩展为空字符串,make继续解析内容。在这里它找到值
$(value)
,并展开该值<代码>值
现在具有来自评估的结果,而不是评估文本本身,因此这将被展开

也许这会有帮助:

value = $(eval value := $(shell cat shelve))$(value)
此处
value
包含字符串
$(评估值:=$(shell cat shelve))$(值)

现在展开它:

%.out: %
        echo $(value) > $< ...
首先,它展开了
eval
,解析如下:

value := $(shell cat shelve)
变量设置为简单展开的变量,因此RHS立即展开。假设
cat shelve
的结果为“foo”,因此
value
现在设置为
foo
(并且标记为简单展开)


这是评估的结束,然后make开始下一部分,即
$(value)
,因此它查找变量
value
,发现它是一个简单的扩展变量,值为
foo

@nowox抱歉,我跳枪了。为什么你会拒绝一个有效的解决方案?也许如果你详细说明原因,我们可以找到一个好的解决办法。这可能是一个X-Y问题。原因是我有几十个目标,其中一些取决于一些
变量,而另一些则不是。使用条件使Makefile很难读取,而且要复杂得多。@nowox-Hmm。那么我的方法可能是一些开箱即用的思想:如何通过确定和删除慢变量的依赖关系并尝试缓存结果来加快慢变量的速度。对,这是我正在努力解决的问题。实际上,我的问题是这个变量的值来自一个Python脚本,该脚本提取并验证一段信息