代码之家  ›  专栏  ›  技术社区  ›  merlin2011

如何对Makefile目标进行基准测试?

  •  0
  • merlin2011  · 技术社区  · 3 年前

    考虑以下Makefile:

    test:
        @echo "$(shell date) Before test"
        sleep 10
        @echo "$(shell date) After test"
    

    当我运行此程序时,输出如下:

    Wed Nov 24 17:00:22 PST 2021 Before test
    sleep 10
    Wed Nov 24 17:00:22 PST 2021 After test
    

    看起来像 make 正在执行shell命令 之前 执行目标。

    我怎么能强迫 制作 当shell命令出现在配方中时执行它们?

    1 回复  |  直到 3 年前
        1
  •  2
  •   Renaud Pacalet    3 年前

    Make配方在将它们传递到外壳之前通过Make进行扩展。因此,当make扩展你的第一个食谱时,食谱变成:

        @echo "Wed Nov 24 17:00:22 PST 2021 Before test"
        sleep 10
        @echo "Wed Nov 24 17:00:22 PST 2021 After test"
    

    因为 date 几乎同时调用。只有在配方被扩展后,它才会被传递到外壳中。在这种情况下,每一行都由不同的shell执行。最后一个在其他字符串之后10秒执行,但由于要回显的字符串已经设置。。。

    Make在将配方传递到外壳之前对其进行扩展,理由非常充分。例如,替换自动生成的变量,如 $@ (规则的目标)或 $^ (规则的先决条件)的实际值。外壳无法做到这一点。

    为了获得所需的效果,正如你自己意识到的那样,你需要让配方本身调用 日期 ,例如与 $(date) 或者用老式的反唇相讥。请注意,您必须逃离 $ 签署以保护其免受make扩展的影响:

    @echo foobar."$$(date)"
    

    其在进行膨胀后变为:

    @echo foobar."$(date)"
    

    这就是为什么人们仍然经常在制作食谱时使用反调,即使 $(...) 现在建议使用语法进行命令替换;没有必要逃避它们:

    @echo foobar."`date`"
    

    使用 $(shell ...) 配方中的make函数是无用的。食谱已经是shell脚本了。与大多数make函数相同。在配方中使用它们的唯一原因是它们比外壳更高效或更简单。但我们必须记住,它们是由make本身扩展的,而不是由shell扩展的,make在配方传递到shell之前对它们进行扩展。示例:如果要打印所有先决条件的基本名称,则 notdir make功能很方便:

    @echo $(notdir $^)
    

    而不是

    @for f in $^; do basename "$$f"; done
    

    但是您不能在中打印所有C源文件的基本名称 ./project/src 具有

    @$(notdir find ./project/src -name '*.c')
    

    bacause make应用其 notdir 每个(扩展的)单词参数的函数,以及它传递给shell的内容是:

    @find src -name '*.c'
    

    这个 find 然后使用错误的起始目录执行命令( src 而不是 ./project/src )而且,即使存在这个错误的起始目录,结果的目录部分也不会被剥离 notdir 其已经被扩展。

        2
  •  0
  •   merlin2011    3 年前

    看起来以下内容达到了预期效果。

    test:
        @echo "$$(date) Before test"
        sleep 10
        @echo "$$(date) After test"
    

    不过,我对其他答案很好奇,如果有不那么棘手的方法可以做到这一点的话。