我有一个需要很长时间才能完成的 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)
这是你可以玩的一个技巧:
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。
| 归档时间: |
|
| 查看次数: |
455 次 |
| 最近记录: |