【发布时间】:2010-12-27 22:02:09
【问题描述】:
是否可以对 makefile 中的变量执行一些操作? 例如,定义
JPI=4
JPJ=2
是否可以在同一个makefile中定义一个变量JPIJ等于$(JPI)*$(JPJ)的扩展值?
【问题讨论】:
标签: makefile
是否可以对 makefile 中的变量执行一些操作? 例如,定义
JPI=4
JPJ=2
是否可以在同一个makefile中定义一个变量JPIJ等于$(JPI)*$(JPJ)的扩展值?
【问题讨论】:
标签: makefile
SHELL=/bin/bash
JPI=4
JPJ=2
all:
echo $$(( $(JPI) * $(JPJ) ))
第一行是choose the Bash shell instead of the default (sh)。通常, sh 不支持算术扩展。但是在 Ubuntu 中,/bin/sh 由 Dash, which supports this feature 提供。因此可以跳过该行。
双美元符号是因为我们想要the expansion to be done by the shell。注意:JPI 和 JPJ 变量先通过 make 展开,然后表达式传递给 bash,如下所示:
$(( 4 * 2 ))
【讨论】:
sh 确实支持 arithmetic expansion。
如果您使用的是 GNU make 并在您的系统上安装了 bc,您可以使用这样的东西:
JPI=4
JPJ=2
FOO=$(shell echo $(JPI)\*$(JPJ) | bc)
all:
echo $(FOO)
【讨论】:
$(shell expr $(JPI) \* $(JPJ))
bc,但我可以看到expr 如果您正在做简单的以 10 为底的整数运算可能更方便(这个问题就是这种情况) .
@mrkj 的回答很好,但正如@Daniel 提到的,并非所有系统都有bc(例如,我在 MSys 上没有)。
我找到了以下两种方法,都使用了shell:$$(( ... ))和expr ...
JPI=4
JPJ=2
#With Double-dollar
JPIJ_1 = $(shell echo $$(( $(JPI) + $(JPJ) )))
#With 'expr'
JPIJ_2 = $(shell expr $(JPI) + $(JPJ) )
$(info Sum with Double-$$: $(JPIJ_1))
$(info Sum with 'expr': $(JPIJ_2))
请注意,当使用expr 时,您应在+ 周围放置空格,否则它将返回4+2。使用 $$ 时不需要这样做。
.
当您有可用的bc 时,您肯定会选择它。我发现以下页面非常有趣:http://www.humbug.in/2010/makefile-tricks-arithmetic-addition-subtraction-multiplication-division-modulo-comparison/
【讨论】:
expr ... 由您的 shell 执行,因此会受到名称扩展的影响,例如expr 2 * 3 将导致错误而不是预期的输出,因为 * 被 shell 扩展为当前目录中的所有文件名。您需要转义运算符 expr 2 \* 3 或将整个表达式放在单引号 expr '2 * 3' 中。
它很笨拙(或者很聪明,取决于你的观点),但你可以直接在 GNU make 中进行算术运算。见Learning GNU Make Functions with Arithmetic。请注意,尽管这种方法不能很好地扩展。正如您在问题中显示的那样,它对于小数字非常有效,但是当您处理大数字(大于 10,000,000)时效果不佳。
【讨论】:
在支持 Guile 的 GNU Make 中(即从 4.0 版开始),很容易使用调用 Scheme 语言进行算术或其他计算。它是在不创建任何子shell或子进程的情况下完成的。
一个例子
JP-I := 4
JP-J := 2
JP-IJ := $(guile (* $(JP-I) $(JP-J) ))
$(info JP-IJ = $(JP-IJ) )
# prints: JP-IJ = 8
另请参阅 Guile Arithmetic Functions 的手册。
Guile 的可能检查:
ifeq (,$(filter guile,$(.FEATURES)))
$(error Your Make version $(MAKE_VERSION) is not built with support for Guile)
endif
【讨论】:
GNU Make Standard Library 提供整数运算功能。
include gmsl
JPI = 4
JPJ = 2
JPIJ = $(call plus,$(JPI),$(JPJ))
【讨论】:
使用makepp 会容易得多。您可以直接访问底层 Perl 解释器。在这种情况下,makeperl 函数在评估为 Perl 之前会进行变量扩展,perl 函数 OTOH 只会评估:
JPI=4
JPJ=2
JPIJ = $(makeperl $(JPI)*$(JPJ))
&echo result: $(JPIJ)
您可以在规则之外使用内置的 &echo 命令作为语句。
【讨论】:
要向池中添加迟到的答案:The GNUmake table toolkit 具有许多算术函数。您可以加、减、乘、除、取以 8,10 和 16 为底的模数。还有常用的二进制运算and、or、xor 和not。数字可以是 60 位左右,但如果您需要更多,您可以调整它。代码是纯 GNUmake 语法,因此可以在 Windows 和 Unix 之间移植,这与 shell 脚本相反——如果你想计算数字,可能会有更好的解决方案;)当然。
这是一个例子:
include gmtt/gmtt.mk
NUMBER_A := -12392834798732429827442389
NUMBER_B := 984398723982791273498234
$(info $(call add,$(NUMBER_A),$(NUMBER_B)))
$(info $(call sub,$(NUMBER_A),$(NUMBER_B)))
$(info $(call mul,$(NUMBER_A),$(NUMBER_B)))
$(info $(call div,$(NUMBER_A),$(NUMBER_B)))
$(info $(call mod,$(NUMBER_A),$(NUMBER_B)))
输出:
$ make
-11408436074749638553944155
-13377233522715221100940623
-12199490762401735834920873237276176262117128241026
-12
-580050110938934545463581
【讨论】: