在makefile中的每个目标之前和之后运行

时间:2018-03-08 00:24:55

标签: shell makefile

我想在makefile中的每个目标之前和之后运行一个命令。

这样的事情

pre:
       @echo pre
       @echo running | mailx -s "Start {target}" user@foo.com
post:
       @echo post
       @echo post | mailx -s "Finish {target}" user@foo.com
j:
       long_running_command && echo $@ > $@
k: j
       long_running_command2 && echo $@ > $@

我想为j和k运行pre和post。理想情况下,我希望收到每个启动和停止任务的电子邮件。

2 个答案:

答案 0 :(得分:2)

一种方法是修改makefile中的所有配方以调用某些命令。您可以将其放入变量中,因此它看起来不太粗糙:

START = mailto --subject 'Started target $@' me@my.host
END = mailto --subject 'Finished target $@' me@my.host

j:
        $(START)
        long_running_command && echo $@ > $@
        $(END)
k: j
        $(START)
        long_running_command2 && echo $@ > $@
        $(END)

关于这一点的好处是你可以选择你想要的目标;也许他们中的一些人不需要它。缺点是如果命令失败,你就不会得到任何结果"电子邮件。

如果您真的想为每个目标执行此操作,那么您可以编写一个shell脚本来模拟shell的行为,同时还可以在运行命令时发送邮件。

$ cat mailshell
#!/bin/sh
# get rid of the -c flag
shift
mailto --subject "started $*" me@my.host
/bin/sh -c "$@"
r=$?
mailto --subject "ended $* with exit code $r" me@my.host
exit $r

(注意这完全没有经过考验,但你得到了我希望的想法)。然后在您的makefile中,将SHELL设置为该shell:

SHELL := mailshell

j:
        long_running_command && echo $@ > $@
k: j
        long_running_command2 && echo $@ > $@

我想你仍然可以通过将SHELL设置为特定于目标的变量来进行选择,只针对那些你想要使用shell的目标。

这样做的一个缺点是,如果您有多行的食谱,您将分别收到每行的电子邮件。您可以通过启用.ONESHELL:强制将整个配方传递到单个shell来解决此问题。但是,我认为这可能需要您的mailshell工具更加复杂。

答案 1 :(得分:1)

如果每个配方只有一个命令,则可以通过更改运行命令的外壳的配置来实现。

让配置文件直接运行pre命令并捕获EXIT以便在其中运行after命令。

例如:

$ cat Makefile
SHELL := BASH_ENV=/dev/fd/3 3<<<'echo before; trap "echo after" EXIT' /bin/bash

default:
  echo default

other:
  echo first
  echo second
$ make default
echo default
before
default
after

但是,如果配方运行多个命令,这可能不是您想要的,因为每次运行之前和之后的代码。

$ make other
echo first
before
first
after
echo second
before
second
after

而且我不知道有一种方法(除了递归Makefile之外),可以使不同的配方使用不同的外壳程序,因此,如果您只想为多个配方设置之前/之后,这将不起作用。