如何使用来自 HTTP 的文件作为 GNU make 的先决条件?

如何使用来自 HTTP 的文件作为 GNU make 的先决条件?

我想使用来自全球资讯网作为我的 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是否存在(因为我们将在-zin 中使用它),如果不存在则curl创建它。touch触摸创建的时间戳为 00:00(当天上午 12 点)。

然后,它使用( )curl选项仅下载自上次下载以来已修改的内容。 可以给出实际的日期表达式或文件名。如果给定文件名,它将使用文件的修改时间作为时间条件。 -z--time-condexample.gz-z

之后,如果local.dat不存在,它将使用 来创建它touch,并使用保证为的时间戳较老的比 的example.gz。这是必要的,因为local.dat必须存在下一个命令才能用来stat获取其 mtime 时间戳。

然后,如果example.gz时间戳比 更新local.dat,则它会example.gz通过管道transmogrify将输出重定向到local.dat

最后,它进行簿记和清理工作:

  • 它会截断example.gz(因为您只需要保留时间戳,而不是整个文件)
  • touchesexample.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

相关内容