GNU中的变量的减法和回声差异

时间:2015-09-25 16:26:56

标签: makefile gnu

我回应运行任务之前的时间以及任务结束的时间: test: @echo $(shell date) @JUNIT_REPORT_PATH=test/report.xml ./node_modules/.bin/mocha test/integration @echo $(shell date) 有没有办法将日期存储在2个变量中,然后显示它们之间的经过时间? 我认为它看起来像这样:

test:
    $begin = $(shell date)
    <do stuff>
    $end = $(shell date)
    @echo $end - $begin

对Make的良好文档的任何指示也将受到赞赏。

谢谢!

3 个答案:

答案 0 :(得分:3)

简短的回答:你想要的是什么:

test:
    @begin=$$(date +%s); \
    <do stuff in same shell: do not forget the ";" and the "\">; \
    end=$$(date +%s); \
    echo $$((end - begin))

答案很长:很抱歉这个问题很长,我认为你的问题应该得到解决,因为你的示例解决方案有很多东西需要解决。

我假设你使用bash,你的make调用bash来执行你的食谱,你的date命令来自GNU coreutils。如果没有,以下内容可能无法按预期工作。如果您在Mac OS X下,请询问有关如何使用最新版本的bash和GNU coreutils而不是默认版本的另一个问题。

回到你的问题。让我们研究一下您的示例解决方案:

test:
    $begin = $(shell date)
    <do stuff>
    $end = $(shell date)
    @echo $end - $begin

并逐步修复需要修复的内容。有几点需要考虑和理解:

1)如何使用make变量:make变量已分配name = value,并使用$(name)${name}进行扩展。请注意,如果您使用单字母变量名称A,则还可以使用$A展开它。因此,当make展开示例配方的第一行$begin = $(shell date)时,结果取决于make变量b是否存在且是否具有非空值。因此,make会将该行扩展为fooegin = <value>egin = <value>。我们首先删除第一个$begin = $(shell date)

来解决此问题

2)可以分配make变量:不在食谱中。因此,在您编写的配方中,beginend是shell变量。并且shell变量分配有name=value,而不是name = value。空间不足。在您的示例中,当make将begin = <value>传递给shell时,您将收到begin: command not found错误。让我们通过删除空格来解决这个问题:begin=$(shell date)

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

4)如何使用bash算术扩展$((end - begin))计算shell变量endbegin之间的差异。让我们通过@echo $((end - begin))替换食谱的最后一行来解决这个问题。可是等等!这将无法工作,因为make会在将它传递给shell之前尝试扩展它,并猜测是什么,它会将(end - begin视为make变量名称并将其展开为无,因为没有这样的make变量。所以make会通过

echo )

到shell,你会得到一个语法错误。要解决此问题,我们必须将$符号加倍:@echo $$((end - begin))。请注意,make有时会扩展一次以上。在这些情况下,您需要更多$个符号:@echo $$$$((end - begin))进行双重扩展。但事实并非如此。

5)当make扩展其变量和函数时:make在需要它们的值时扩展其变量和函数,而不是在你想到的时候。这是在执行食谱之前。因此,在您的示例中,beginend将具有相同的值,无论<do stuff>采用什么时间,它都将是展开展开{{1}的瞬间的日期和时间}。尝试:

$(shell date +%s)

并看到两个时间戳是相同的。我们不使用test: @echo $(shell date +%s) @sleep 2 @echo $(shell date +%s) $(shell)(请注意begin=$$(date +%s))来解决此问题。 make会将其展开为$$并将其传递给shell。 shell将按照您的想法执行,并且在shell调用的瞬间将为begin=$(date +%s) shell变量分配当前时间戳。

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

;

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

对于很长的食谱,这不是很方便。别担心,你可以打破界限,但最后字符必须是@告诉make忽略换行符:

\

前面的配方在单个shell调用中执行。 shell变量target: @<do this>; <do that>; baz=1; \ <and also this>; \ if <condition>; then \ <do this>; \ else \ <do that>; \ fi; \ <and this>; \ echo $$baz 从头到尾是相同的变量。初始baz仍然禁用整个shell命令列表的回显。尝试:

@

并看到它的工作方式与单行版本相同。 警告test: @begin=$$(date +%s); \ sleep 2; \ end=$$(date +%s); \ echo $$((end - begin)) 必须在换行符之前 。在\之后添加一两个空格非常容易。如果你这样做,你将得到shell错误。最糟糕的是,几乎不可能理解和调试。因此,如果您对这种配方有奇怪的错误,请搜索行尾的空格。如果您知道如何执行此操作,请告诉编辑在makefile中的行末尾突出显示空白。

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

\

应该做你想做的事。首先记下初始test: @begin=$$(date +%s); \ <do stuff in same shell: do not forget the ";" and the "\">; \ end=$$(date +%s); \ echo $$((end - begin)) 并禁用回显,然后将配方扩展为一个命令列表:

@

并以唯一的调用将其传递给shell。

最后一个重要的评论:因为有一个shell调用它也快得多。如果你有复杂的makefile执行复杂的事情,它可以产生显着的差异。如果可以,请始终使用此功能,并加快处理速度。

答案 1 :(得分:1)

如果你只是想要花时间,我建议你/usr/bin/time(不是time的shell版本),例如。

/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'

我只想在这里分享/ usr / bin / time。应该适合简单的食谱。

答案 2 :(得分:0)

算术运算可以在makefile中完成,如下所示。

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}

礼貌:Makefile Tricks: Arithmetic – Addition, Subtraction, Multiplication, Division, Modulo, Comparison