如何编写一个Makefile规则,以仅在文件缺失时下载该文件?

15
我正在尝试编写一个Makefile,如果缺少某些源文件,则应下载它们。
类似如下内容:
hello: hello.c
    gcc -o hello hello.c

hello.c:
    wget -O hello.c http://example.org/hello.c

当然这会导致每次运行make命令时都会下载hello.c。我希望只有在hello.c不存在时,该Makefile才会下载hello.c。使用GNU make是否可能实现,如果可能的话该如何实现?

4个回答

16

我猜想 wget 并没有更新 hello.c 文件的时间戳,而是保留了远程文件的时间戳。这导致 make 认为 hello.c 是旧的并尝试重新下载它。请尝试:

hello.c:
        wget ...
        touch $@

编辑:使用wget的选项-N可以防止wget下载除非远程文件较新(但它仍然会检查远程文件的时间戳)。


抱歉直言,像那样模糊的问题只会引来一堆猜测。 - JesperE
5
答案是错误的,因为在文件名为"hello.c"的文件已经存在的情况下(无论其时间戳如何),目标hello.c:不会被重新制作(且文件未被下载)。 第二个原因是使用-O选项时,文件的时间戳始终与下载时间重合。 - P Shved
但由于问题本身就是错误的,所以我并不惊讶错误的答案竟然是正确的。>_< - P Shved
1
Pavel,wget 1.15即使带有“-O”选项也会保留时间戳。尽管如此,您依然正确,make不会查看时间戳(没有其他可供make进行比较的时间戳)。 - proski

7
您编写的 Makefile 只有在缺失 hello.c 时才会下载。也许您还有其他错误?例如,请参阅:
hello: hello.c
        gcc -o hello hello.c

hello.c:
        echo 'int main() {}' > hello.c

同时:

% make
echo 'int main() {}' > hello.c
gcc -o hello hello.c
% rm hello
% make
gcc -o hello hello.c
% rm hello*
% make
echo 'int main() {}' > hello.c
gcc -o hello hello.c

(第二次未执行echo命令)

我太傻了,忘记运行这个简单的测试了。看起来wget正在搞乱文件日期...谢谢! - abbot
这不会破坏功能。 - Lukáš Lalinský

7

既然Makefile应该按照你的要求工作,你需要检查一些不太可能的情况:

1)检查你是否有任何提及源文件的.PHONY规则。

2)检查源目标名称是否与你正在下载的文件路径匹配。

你也可以尝试运行make -d命令,以查看为什么make认为需要“重新构建”源文件。


1
还要确保wget不会失败,并且在-O后面的名称与目标匹配。最好使用$@而不是hello.cwget命令中。 - proski

2

如果hello.c的前提条件发生了变化或为空,并且Make在文件存在时继续下载,则防止Make重新下载文件的一种方法是在目标体中使用一个标志来检测文件是否存在:

hello.c:
    test -f $@ || wget -O hello.c http://example.org/hello.c

test 命令将返回 true 如果文件 hello.c 存在,否则它将返回 false 并运行 wget 命令。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接