如何对 Makefile 目标进行基准测试?
How do I benchmark Makefile targets?
考虑以下 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 命令。
如何强制 make
执行出现在食谱中的 shell 命令?
看来下面达到了想要的效果
test:
@echo "$$(date) Before test"
sleep 10
@echo "$$(date) After test"
我对其他答案很好奇,但如果有更少的 hacky 方法可以做到这一点。
通过先将 Make 方法传递给 shell 来扩展 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。在这种情况下,每一行都由不同的 shell 执行。最后一个在其他 10 秒后执行,但因为要回显的字符串已经设置...
Make 在将食谱传递给 shell 之前对其进行了扩展,这是有充分理由的。例如,用它们的实际值替换像 $@
(规则的目标)或 $^
(规则的先决条件)这样的自动 make 变量。 shell 无法做到这一点。
要获得所需的效果,正如您自己意识到的那样,您需要让食谱本身调用 date
,例如使用 $(date)
或使用老式的反引号。请注意,您必须转义 $
符号以保护它不受 make 扩展的影响:
@echo foobar."$$(date)"
展开后变成:
@echo foobar."$(date)"
这就是为什么人们仍然经常在 make 配方中使用反引号,即使现在建议使用 $(...)
语法进行命令替换;没有必要逃避他们:
@echo foobar."`date`"
在配方中使用 $(shell ...)
make 函数是没有用的。食谱已经是 shell 个脚本。与大多数 make 函数相同。在食谱中使用它们的唯一原因是当它们比 shell 等价物更有效或更简单时。但是我们必须记住,它们是由 make 本身扩展的,而不是 shell,并且 make 在将配方传递给 shell 之前扩展了它们。示例:如果您想打印所有先决条件的基本名称,notdir
make 函数很方便:
@echo $(notdir $^)
而不是:
@for f in $^; do basename "$$f"; done
但是您不能打印 ./project/src
中所有 C 源文件的基本名称:
@$(notdir find ./project/src -name '*.c')
因为 make 将它的 notdir
函数应用于它的每个(扩展的)单词参数,它传递给 shell 的是:
@find src -name '*.c'
然后执行 find
命令时使用错误的起始目录(src
而不是 ./project/src
),即使存在这个错误的起始目录,结果的目录部分没有被已经展开的notdir
剥离。
考虑以下 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 命令。
如何强制 make
执行出现在食谱中的 shell 命令?
看来下面达到了想要的效果
test:
@echo "$$(date) Before test"
sleep 10
@echo "$$(date) After test"
我对其他答案很好奇,但如果有更少的 hacky 方法可以做到这一点。
通过先将 Make 方法传递给 shell 来扩展 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。在这种情况下,每一行都由不同的 shell 执行。最后一个在其他 10 秒后执行,但因为要回显的字符串已经设置...
Make 在将食谱传递给 shell 之前对其进行了扩展,这是有充分理由的。例如,用它们的实际值替换像 $@
(规则的目标)或 $^
(规则的先决条件)这样的自动 make 变量。 shell 无法做到这一点。
要获得所需的效果,正如您自己意识到的那样,您需要让食谱本身调用 date
,例如使用 $(date)
或使用老式的反引号。请注意,您必须转义 $
符号以保护它不受 make 扩展的影响:
@echo foobar."$$(date)"
展开后变成:
@echo foobar."$(date)"
这就是为什么人们仍然经常在 make 配方中使用反引号,即使现在建议使用 $(...)
语法进行命令替换;没有必要逃避他们:
@echo foobar."`date`"
在配方中使用 $(shell ...)
make 函数是没有用的。食谱已经是 shell 个脚本。与大多数 make 函数相同。在食谱中使用它们的唯一原因是当它们比 shell 等价物更有效或更简单时。但是我们必须记住,它们是由 make 本身扩展的,而不是 shell,并且 make 在将配方传递给 shell 之前扩展了它们。示例:如果您想打印所有先决条件的基本名称,notdir
make 函数很方便:
@echo $(notdir $^)
而不是:
@for f in $^; do basename "$$f"; done
但是您不能打印 ./project/src
中所有 C 源文件的基本名称:
@$(notdir find ./project/src -name '*.c')
因为 make 将它的 notdir
函数应用于它的每个(扩展的)单词参数,它传递给 shell 的是:
@find src -name '*.c'
然后执行 find
命令时使用错误的起始目录(src
而不是 ./project/src
),即使存在这个错误的起始目录,结果的目录部分没有被已经展开的notdir
剥离。