Makefile GNU Make中变量的减法和回显差

Makefile GNU Make中变量的减法和回显差,makefile,gnu,Makefile,Gnu,我在回显运行任务前的时间和任务结束的时间: 测试: @echo$(外壳日期) @JUNIT_REPORT_PATH=test/REPORT.xml./node_modules/.bin/mocha test/integration @echo$(外壳日期) 有没有办法将日期存储在两个变量中,然后显示它们之间经过的时间? 我想它看起来是这样的: test: $begin = $(shell date) <do stuff> $end = $(shell da

我在回显运行任务前的时间和任务结束的时间:

测试:
@echo$(外壳日期)
@JUNIT_REPORT_PATH=test/REPORT.xml./node_modules/.bin/mocha test/integration
@echo$(外壳日期)
有没有办法将日期存储在两个变量中,然后显示它们之间经过的时间? 我想它看起来是这样的:

test:
    $begin = $(shell date)
    <do stuff>
    $end = $(shell date)
    @echo $end - $begin
测试:
$begin=$(shell日期)
$end=$(外壳日期)
@echo$end-$begin
任何关于Make的好文档都将不胜感激


谢谢

简短回答:你想要的是可能的:

test:
    @begin=$$(date +%s); \
    <do stuff in same shell: do not forget the ";" and the "\">; \
    end=$$(date +%s); \
    echo $$((end - begin))
一步一步地解决需要解决的问题。有一些事情需要考虑和理解:

1) 如何使用make变量:make变量用
name=value
赋值,并用
$(name)
${name}
展开。请注意,如果您有一个单字母变量名
a
,也可以使用
$a
展开它。因此,当make展开示例配方的第一行时,
$begin=$(shell日期)
结果取决于make变量
b
是否存在且是否具有非空值。make将因此将行扩展为
footegin=
egin=
。让我们通过删除第一个
$
begin=$(shell日期)
来解决这个问题

2) 可以指定make变量的位置:不在配方中。因此,在您编写的配方中,
begin
end
是shell变量。而shell变量被赋值为
name=value
,而不是
name=value
。没有空间。在您的示例中,当make将
begin=
传递到shell时,您将得到一个
begin:command not found
错误。让我们通过删除空格来解决这个问题:
begin=$(shell日期)

3) 如何使用日期:默认格式不适用于算术。使用
date+%s
返回当前日期-时间作为时间戳(自历元起的秒数)。让我们用
begin=$(shell日期+%s)
来解决这个问题

4) 如何使用bash算术展开
$((end-begin))
计算shell变量
end
begin
之间的差异。让我们用
@echo$((end-begin))
替换食谱的最后一行来解决这个问题。但是等等!这将不起作用,因为在将它传递给shell之前,它会尝试扩展它,并且猜测它会考虑<代码>(结束-开始<代码>作为一个生成变量名,并将其扩展为没有,因为没有这样的生成变量。
echo )
若要修复此问题,我们必须将
$
符号加倍:
@echo$$((end-begin))
。请注意,make有时扩展不止一次。在这些情况下,您需要更多
$
符号:
@echo$$$((end-begin))
进行双重make扩展。但这不是您的情况

5) 当make扩展其变量和函数时:make在需要变量和函数的值而不是思考时扩展其变量和函数。这是在执行配方之前。因此,在您的示例中,
开始
结束
将具有相同的值,无论
花费多少时间,它都将是使扩展的
$(外壳日期+%s)
的日期和时间。尝试:

test:
    @echo $(shell date +%s)
    @sleep 2
    @echo $(shell date +%s)
请注意这两个时间戳是相同的。我们不使用
$(shell)
begin=$$(date+%s)
(注意
$
)。make将其展开为
begin=$(日期+%s)
,并将其传递给shell。shell将按照您的想法进行操作,
begin
shell变量将在shell调用时被分配当前时间戳

6) make如何处理配方:每一行在扩展后传递到不同的外壳。是的,在您的示例中,至少有4个不同的shell调用。如果
隐藏多行,则会显示更多信息。这里的问题是,对于将执行最后一行的shell,我们的
begin
end
shell变量不存在,您将得到另一个shell错误。让我们通过将所有shell命令放在同一行上,用
分隔来解决这个问题外壳分隔符:

test:
    @begin=$$(date +%s); sleep 2; end=$$(date +%s); echo $$((end - begin))
宾果!它开始工作了。请注意,初始的
@
将禁用整个shell命令列表的回显

然而,对于很长的食谱来说,这不是很方便。别担心,您可以换行,但是最后一个字符必须是
\
才能告诉make忽略换行:

target:
    @<do this>; <do that>; baz=1; \
    <and also this>; \
    if <condition>; then \
      <do this>; \
    else \
      <do that>; \
    fi; \
    <and this>; \
    echo $$baz
并确保其工作方式与单线版本类似警告
\
必须真正在换行之前。在
\
之后添加一两个空格非常容易。如果这样做,您将得到shell错误。最糟糕的是,几乎不可能理解和调试。因此,如果您在这类食谱中有奇怪的错误,请搜索行尾的空格。如果您知道如何执行此操作,请告诉编辑器高亮显示makefiles中行末尾的空格

我们差不多完成了。总而言之

test:
    @begin=$$(date +%s); \
    <do stuff in same shell: do not forget the ";" and the "\">; \
    end=$$(date +%s); \
    echo $$((end - begin))
并以独特的调用将其传递给shell


最后一点很重要:因为只有一个shell调用,所以速度也快得多。如果您有复杂的makefile来做复杂的事情,那么它可以带来显著的不同。如果可以,请始终使用此选项,并加快处理速度。

简短回答:您想要的是可能的:

test:
    @begin=$$(date +%s); \
    <do stuff in same shell: do not forget the ";" and the "\">; \
    end=$$(date +%s); \
    echo $$((end - begin))
一步一步地解决需要解决的问题。有一些事情需要考虑和理解:

1) 如何使用make变量:make变量用
name=value
赋值,并用
$(name)
${name}
展开。请注意,如果您有一个单字母变量
test:
    @begin=$$(date +%s); \
    <do stuff in same shell: do not forget the ";" and the "\">; \
    end=$$(date +%s); \
    echo $$((end - begin))
begin=$(date +%s); <do stuff>; end=$(date +%s); echo $((end - begin))
/usr/bin/time -f "%E real,%U user,%S sys" g++ something
/usr/bin/time -f "%E real,%U user,%S sys" sh -c 'g++ a; g++ b'
NUMBER1 := 10
NUMBER2 := 5

#Addition
ADD := $(shell echo ${NUMBER1}+${NUMBER2} | bc)

#Subtraction
SUBTRACT := $(shell echo ${NUMBER1}-${NUMBER2} | bc)

#Multiplication
MULTIPLY := $(shell echo ${NUMBER1}*${NUMBER2} | bc)

#Division
DIVIDE := $(shell echo ${NUMBER1}/${NUMBER2} | bc)

#Division (Floating Point)
DIVIDEF := $(shell echo "scale=3; ${NUMBER2}/${NUMBER1}" | bc)

#Modulo
MODULO := $(shell echo ${NUMBER1}%${NUMBER2} | bc)

#Comparison Greater Than
COMPARISON1 := $(shell echo ${NUMBER1}\>=${NUMBER2} | bc)

#Comparison Smaller Than
COMPARISON2 := $(shell echo ${NUMBER2}\<=${NUMBER2} | bc)

all:
  @echo Addition ${ADD}
  @echo Subtraction ${SUBTRACT}
  @echo Multiplication ${MULTIPLY}
  @echo Division ${DIVIDE}
  @echo Division  - Floating Point ${DIVIDEF}
  @echo Modulo ${MODULO}
  @echo Comparison Greater Than ${COMPARISON1}
  @echo Comparison Smaller Than ${COMPARISON2}