Lor*_*ein 5 shell make io-redirection
在 makefile 中,我有几个如下所示的规则:
out.txt: foo.sh input.txt
./foo.sh -i input.txt > out.txt
Run Code Online (Sandbox Code Playgroud)
如果foo.sh
失败,out.txt
则将创建为 0 大小的文件。如果我再次运行make,它会错误地认为out.txt
文件创建成功,并且不会再次运行规则。
处理这种情况的正确方法是什么?
Mic*_*zek 11
您可以要求,使删除目标文件,如果规则失败,通过定义一个特殊的目标命名.DELETE_ON_ERROR
。它不需要执行任何操作或具有任何依赖项,因此只需将其添加到您的 makefile 中:
.DELETE_ON_ERROR:
Run Code Online (Sandbox Code Playgroud)
然后你会得到以下信息:
.DELETE_ON_ERROR:
Run Code Online (Sandbox Code Playgroud)
从食谱错误:
通常,当配方行失败时,如果它完全更改了目标文件,则该文件已损坏且无法使用——或者至少它没有完全更新。然而文件的时间戳表示它现在是最新的,所以下次
make
运行时,它不会尝试更新该文件。这种情况就和shell被信号杀死时一样;见中断。所以通常正确的做法是如果在开始更改文件后配方失败,则删除目标文件。make
如果.DELETE_ON_ERROR
出现为目标,将执行此操作。这几乎总是你想做的make
,但这不是历史实践;所以为了兼容性,你必须明确要求它。
只要有可能,makefile 规则应该首先在一个临时名称下创建它们的目标,然后将其移动到位。这样,如果构建过程因任何原因中断,则不会出现无法与完全写入的文件区分开的半写入目标文件。
out.txt: foo.sh input.txt
./foo.sh -i input.txt >$@.tmp
mv -f $@.tmp $@
Run Code Online (Sandbox Code Playgroud)
mv -f $@.tmp $@
是一个常见的 makefile 习惯用法。
Juliano 的回答显示了一个变体,其中临时文件的名称是动态生成的。如果可能有多个进程生成相同的目标或者目录可以被其他用户写入,则需要动态名称生成。构建树很少出现这种情况(如果这些是问题,典型的 makefile 中发生的很多事情都会中断),因此通常不需要额外的复杂性。
归档时间: |
|
查看次数: |
270 次 |
最近记录: |