Makefile 如何在生成文件中执行算术?

Makefile 如何在生成文件中执行算术?,makefile,Makefile,是否可以对makefile中的变量执行某些操作? 例如,定义 JPI=4 JPJ=2 是否可以在同一makefile中定义一个变量JPIJ,该变量等于扩展值$(JPI)*$(JPJ)?如果您使用的是GNUmake,并且在系统上安装了bc,您可以使用类似的方法: JPI=4 JPJ=2 FOO=$(shell echo $(JPI)\*$(JPJ) | bc) all: echo $(FOO) $(( 4 * 2 )) 它很笨拙(或者很聪明,取决于你的视角),但是你可以直接在GNUMak

是否可以对makefile中的变量执行某些操作? 例如,定义

JPI=4
JPJ=2

是否可以在同一makefile中定义一个变量
JPIJ
,该变量等于扩展值
$(JPI)*$(JPJ)

如果您使用的是GNU
make
,并且在系统上安装了
bc
,您可以使用类似的方法:

JPI=4
JPJ=2
FOO=$(shell echo $(JPI)\*$(JPJ) | bc)
all:
  echo $(FOO)
$(( 4 * 2 ))
它很笨拙(或者很聪明,取决于你的视角),但是你可以直接在GNUMake中做算术。看见但是请注意,这种方法不能很好地扩展。如您在问题中所示,它对小数字非常有效,但在处理大数值(大于10000000)时效果不佳。

使用它更容易。您可以直接访问底层Perl解释器。在这种情况下,makeperl函数在作为Perl求值之前进行变量扩展,Perl函数OTOH只求值:

JPI=4
JPJ=2
JPIJ = $(makeperl $(JPI)*$(JPJ))
&echo result: $(JPIJ)
您可以在规则之外使用内置&echo命令作为语句。

使用:

第一行是去。通常,sh不支持算术展开。但是在Ubuntu中,/bin/sh是由提供的。这样就可以跳过这一行

双美元符号是因为我们想要。注意:JPI和JPJ变量首先通过make展开,然后将表达式传递给bash,如下所示:

JPI=4
JPJ=2
FOO=$(shell echo $(JPI)\*$(JPJ) | bc)
all:
  echo $(FOO)
$(( 4 * 2 ))
提供整数算术函数

include gmsl

JPI = 4
JPJ = 2

JPIJ = $(call plus,$(JPI),$(JPJ))

@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
时,您肯定会选择它。我发现下面的页面非常有趣:

在GNU Make with support(即自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,请参见手册

可能的欺诈检查:

ifeq (,$(filter guile,$(.FEATURES)))
  $(error Your Make version $(MAKE_VERSION) is not built with support for Guile)
endif

向池中添加最新答案:具有许多算术函数。你可以加,减,乘,除,取基数8,10和16的模数。还有常见的二进制操作
异或
。数字可以是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

六羟甲基三聚氰胺六甲醚。。。。看到makefiles能做数学运算,真是令人惊讶。这不是一个很容易添加的功能吗?@Kamath查看一下,找到一个大数字的实现(大约63个位置,但如果您愿意,您可以有更多)。代码仍然是笨拙的、令人发狂的、笨拙的或可怕的,这取决于您的观点,thoPOSIX
sh
确实支持+1,因为这是最好的解决方案,因为它只依赖于与POSIX兼容的shell。感谢您指出,在make.expr中执行shell算术时,我们需要一个双美元符号。相比于bc,在make.expr中执行shell算术更常见:
$(shell expr$(JPI)\*$(JPJ))
@DanielAlder:有趣的是,我总是使用
bc
,但我可以看出如果您执行简单的10进制整数算术,
expr
可能更方便(这就是这个问题的情况)。哦,天哪……我看到了这个,觉得很棒,一些东西没有经过黑客攻击就建成了它。然后我注意到它是一个SourceForge项目,这个项目只是劫持了它的名字并加上了一些宣传。@MatthewSimoneau'GNU'@Yoyoyoyonny,它是GNU Make的“标准库”。我可以看出“标准库”有点大胆,但“GNU制造”部分只是描述性的。