制作:.DELETE_ON_ERROR用于目录目标

Dan*_*age 6 makefile gnu-make

GNU Make包含一个称为的特殊目标.DELETE_ON_ERROR。如果您的Makefile中包含此文件,Make将删除其构建序列以非零返回状态完成的任何目标。这很有用,因此在以后的调用中,Make不会假定目标已正确构建。

这是一个虚拟的例子。

.DELETE_ON_ERROR:

out.dat:    in.dat
            touch out.dat
            false
Run Code Online (Sandbox Code Playgroud)

因为false给出的返回值非零,所以构建被视为失败,并且Make删除了out.dat目标。这是广告和预期的行为。但是,当目标是目录时,似乎不会保留此行为。考虑另一个虚拟的例子。

.DELETE_ON_ERROR:

outdir/:    in.dat
            mkdir outdir/
            false
Run Code Online (Sandbox Code Playgroud)

在这种情况下,构建会再次失败,但是Make不会删除outdir目录。有什么方法可以指示Make进行此操作吗?

das*_*h-o 1

正如评论中所指出的,很难在目录上使用时间戳。几个选项:

  • 代理目标(%.dir)
  • 使用临时文件夹进行原子更新。

使用代理目标,可以修改 Makefile 以包含“%.done”目标,该目标将嵌入清理逻辑。

.PHONY: %.dir

outdir.dir:
    $(MAKE) outdir ; if [ $? -ne 0 ] ; then echo CLEANUP $@ ; rm -rf dir ; false ; fi

outdir: ...  # as before
Run Code Online (Sandbox Code Playgroud)

并使用 outdir.dir 作为依赖项。不优雅,但会完成工作。可能可以转换为规则(免责声明:我没有测试这种方法)。

.PHONY %.dir

%.dir:
    $(MAKE) $* ; if [ $? -ne 0 ] ; then echo CLEANUP $* ; rmd -rf $* ; false ; fi
Run Code Online (Sandbox Code Playgroud)

另一种变体是更改 outdir 以添加“完成”指示文件(如果成功完成),并使用代理目标来验证

%.dir:
    $(MAKE) $* ; if [ ! -f $*.done ] ; then rm -rf $* ; false ; fi

outdir:
   ... commands, any can fail.
   touch $*.done
Run Code Online (Sandbox Code Playgroud)

作为最后的手段(或第一个选项,具体取决于您的情况),请考虑为 outdir 进行“原子”构建 - 创建一个临时文件夹,并在成功时将其重命名为 outdir

outdir:
    rm -rf $@.new $@
    mkdir $@.new
    # Command to create outdir.new here
    mv $@.new $@
Run Code Online (Sandbox Code Playgroud)