我想使用来自全球资讯网作为我的 makefile 中的先决条件:
local.dat: http://example.org/example.gz
curl -s $< | gzip -d | transmogrify >$@
如果远程文件比本地文件新,我只想“transmogrify”,就像制作正常运行。
我愿意不是想要保留以下内容的缓存副本示例.gz- 文件很大,我不需要原始数据。最好我想完全避免下载该文件。目标是使用 make 标志并行处理其中一些-j
。
什么是解决这个问题的干净方法?我可以想到几个方法:
- 保留一个空的虚拟文件,并在每次重新创建目标时更新
- 一些使用 GNU make 的插件新的插件系统(我对此一无所知)
- 在本地文件系统中安装 HTTP 服务器的与 make 无关的方式
在进一步挖掘之前,我想要一些建议,最好是具体的例子!
答案1
在你的 Makefile 中尝试这样的事情:
.PHONY: local.dat
local.dat:
[ -e example.gz ] || touch -d '00:00' example.gz
curl -z example.gz -s http://example.org/example.gz -o example.gz
[ -e $@ ] || touch -d 'yesterday 00:00' $@
if [ "$(shell stat --printf '%Y' example.gz)" \
-gt "$(shell stat --printf '%Y' $@)" ] ; then \
zcat example.gz | transmogrify >$@ ; \
fi
truncate -s 0 example.gz
touch -r $@ example.gz
(注意:这是一个 Makefile,所以缩进是制表符,而不是空格。当然。同样重要的是,连续行上的后面没有空格\
- 或者去掉反斜杠转义符并使其长,几乎无法阅读的行)
这个 GNUmake
配方首先检查一个名为 的文件example.gz
是否存在(因为我们将在-z
in 中使用它),如果不存在则curl
创建它。touch
触摸创建的时间戳为 00:00(当天上午 12 点)。
然后,它使用( )curl
选项仅下载自上次下载以来已修改的内容。 可以给出实际的日期表达式或文件名。如果给定文件名,它将使用文件的修改时间作为时间条件。 -z
--time-cond
example.gz
-z
之后,如果local.dat
不存在,它将使用 来创建它touch
,并使用保证为的时间戳较老的比 的example.gz
。这是必要的,因为local.dat
必须存在下一个命令才能用来stat
获取其 mtime 时间戳。
然后,如果example.gz
时间戳比 更新local.dat
,则它会example.gz
通过管道transmogrify
将输出重定向到local.dat
。
最后,它进行簿记和清理工作:
- 它会截断
example.gz
(因为您只需要保留时间戳,而不是整个文件) touch
esexample.gz
以便它具有相同的时间戳local.dat
.PHONY 目标确保local.dat
目标始终被执行,即使该名称的文件已存在。
感谢@Toby Speight 在评论中指出我的原始版本无法工作以及原因。
或者,如果您想将文件直接通过管道传输到transmogrify
而不先将其下载到文件系统:
.PHONY: local.dat
local.dat:
[ -e example.gz ] || touch -d '00:00' example.gz
[ -e $@ ] || touch -d 'yesterday 00:00' $@
if [ "$(shell stat --printf '%Y' example.gz)" \
-gt "$(shell stat --printf '%Y' $@)" ] ; then \
curl -z example.gz -s http://example.org/example.gz | transmogrify >$@ ; \
fi
touch -r $@ example.gz
笔记:这大多未经测试,因此可能需要一些小的更改才能使语法完全正确。这里重要的是方法,而不是复制粘贴货物崇拜的解决方案。
几十年来我一直在使用这种方法的变体(即touch
时间戳文件) 。make
它有效,并且通常允许我避免在 sh 中编写自己的依赖项解析代码(尽管我必须在stat --printf %Y
这里做类似的事情)。
每个人都知道make
它是编译软件的绝佳工具...在我看来,它对于系统管理和脚本任务来说也是一个被严重低估的工具。
答案2
另一种替代方法是使用构建系统,该系统使用依赖项校验和来确定是否触发重建。我经常使用 Gnu Make 的“touch”技巧,但是当您可以指定动态依赖项并且不更改的文件不会触发重建时,它会简单得多。这是一个使用的示例好美客:
#! /usr/local/goodmake.py /bin/sh -se
#! *.date
# Get the last-modified date
curl -s -v -X HEAD http://${1%.date} 2>&1 | grep -i '^< Last-Modified:' >$1
#? local.dat
site=http://example.org/example.gz
$0 $site.date
curl -s $site | gzip -d | transmogrify >$1