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

now*_*wox 1 makefile gnu-make

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

一个解决方案是使用而不是声明value一个deferred变量。:==

不幸的是,这不是一个解决方案,因为它会减慢make clean任何其他目标的执行速度2 秒,因为value它没有计算。

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)
Run Code Online (Sandbox Code Playgroud)

如何设置仅在使用时分配但仅计算一次的变量?

换句话说,我想build花 2 秒钟来完成并clean立即完成。

我对涉及条件的解决方案不感兴趣,以便绕过valueif the target is not的分配build

另一种解决方案是这样。不幸的是,在这种情况下,我需要检查shelve文件是否需要重新生成。

value = $(cat shelve)

shelve: 
    sleep 2 && echo 42 > $@ || [ rm $@ -a true ]

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

build: $(out)

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

init:
    touch $(in)

clean:
    rm -vf $(out)
Run Code Online (Sandbox Code Playgroud)

Mad*_*ist 5

这是你可以玩的一个技巧:

value = $(eval value := $(shell cat shelve))$(value)
Run Code Online (Sandbox Code Playgroud)

value是如何工作的:首先使用递归分配进行分配,因此不会扩展 RHS 上的值。

第一次value扩展 make 解析器将首先运行$(eval ...)它,它为 makefile 启动一个“新解析器”。在那个解析器中,内容value := $(cat shelve)被评估。这里,value是一个简单的变量赋值,因此 RHS 立即展开并$(shell ...)运行并分配给value.

记住 make 并没有真正的变量作用域的概念,所以这value只是value我们在外部解析器中设置的同一个全局变量。

然后 eval 完成并扩展为空字符串,然后继续解析内容。在这里,它找到了值$(value)并扩展...value现在有来自 eval 的结果,而不是 eval 文本本身,所以这就是将被扩展的内容。

也许这会有所帮助:

value = $(eval value := $(shell cat shelve))$(value)
Run Code Online (Sandbox Code Playgroud)

这里value包含字符串$(eval value := $(shell cat shelve))$(value)

现在你展开它:

%.out: %
        echo $(value) > $< ...
Run Code Online (Sandbox Code Playgroud)

Make 开始扩展这个配方。它到达$(value)并看到它需要扩展变量value:因为它是递归的,所以它扩展了值:

$(eval value := $(shell cat shelve))$(value)
Run Code Online (Sandbox Code Playgroud)

首先它扩展eval,它解析这个:

value := $(shell cat shelve)
Run Code Online (Sandbox Code Playgroud)

这将value变量设置为简单扩展变量,因此 RHS 立即扩展。假设结果cat shelve是“foo”,所以value现在设置为foo(并且它被标记为简单扩展)。

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