避免重新生成不会更改的文件

发布于 2024-12-07 20:26:41 字数 861 浏览 0 评论 0原文

我有一个包含这种形式的多个规则的 Makefile

protolist.c: $(PROTOCOLS) Makefile src/genmodtable.sh
    $(SHELL) $(srcdir)/src/genmodtable.sh \
        $@ $(filter-out %Makefile %genmodtable.sh, $^)

顾名思义,protolist.c 最终包含由 .c 文件定义的所有“协议”的列表$(协议)。该文件的内容在形式上确实依赖于 $(PROTOCOLS)、Makefile 和生成器脚本中的所有内容,但该文件实际上很少发生更改其中 .c 文件已被编辑。因此,如果 genmodtable.sh 不打算对其内容进行任何更改,则它不会更改 protolist.c 的时间戳。这会导致 Make 在不需要时跳过重建 protolist.o 及其依赖项。

一切正常; 问题是,因为protolist.c现在似乎已经过时了依赖项,Make认为它必须尝试每次运行时重新生成protolist.c。这不是性能问题——脚本非常快——但这是令人困惑的行为。我依稀记得一个涉及时间戳文件的习语,可以用来阻止 Make 执行此操作,但我无法重建它或在任何地方找到它的描述。有谁知道它是什么?

(另外,如果有人可以建议如何摆脱那个愚蠢的 $(filter-out ...) 构造,那将会很有帮助,因为这是这个 Makefile 中唯一的 GNUmakeism。)

I have a Makefile with several rules of this form

protolist.c: $(PROTOCOLS) Makefile src/genmodtable.sh
    $(SHELL) $(srcdir)/src/genmodtable.sh \
        $@ $(filter-out %Makefile %genmodtable.sh, $^)

As the name implies, protolist.c winds up containing a list of all the "protocols" defined by the .c files in $(PROTOCOLS). The contents of this file do formally depend on everything in $(PROTOCOLS), the Makefile, and the generator script, but it's very rare for the file to actually change when one of those .c files is edited. Therefore, genmodtable.sh is coded to not change the timestamp of protolist.c if it's not going to make any change to its contents. This causes Make to skip rebuilding protolist.o and its dependencies when it's not really necessary.

That all works fine; the problem is that, because protolist.c now appears to be out of date with respect to its dependencies, Make thinks it has to try to regenerate protolist.c on every run. This isn't a performance issue -- the script is very fast -- but it is confusing behavior. I dimly recall an idiom, involving timestamp files, that could be used to stop Make from doing this, but I have not been able to reconstruct it or find it described anywhere. Does anyone know what it is?

(Also if anyone can suggest how to get rid of that silly $(filter-out ...) construct, that would be helpful, as that is the only GNUmakeism in this Makefile.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

最终幸福 2024-12-14 20:26:41

这看起来与 Fortran 编程和 make 的问题类似,涉及编译模块时生成的文件。 (不相关,除此之外,我学会了如何执行此操作。)

您想要的是将 protolist.o 的时间戳与 protolist.c 的时间戳进行比较code>,它仍然是“旧的”,并决定运行 protolist.c 的配方,具体取决于时间戳文件的时间戳,每次运行配方时该文件都会更新.
为了使这项工作有效,您必须使用空规则将两者链接在一起。

protolist.o: protolist.c
    [...]

protolist.c: protolist.c.time ;

protolist.c.time: $(PROTOCOLS) Makefile src/genmodtable.sh
    $(SHELL) $(srcdir)/src/genmodtable.sh \
        protolist.c $(filter-out %Makefile %genmodtable.sh, $^)
    touch protolist.c.time

在我自己的 makefile 中,我必须将时间戳文件声明为特殊目标 .PRECIOUS 的先决条件,以防止 make 删除它们,但我使用的是模式规则;我不是 100% 确定,但我认为在使用明确的规则时没有必要,就像这里一样。

为了避免 $(filter-out ...) 构造,您不能简单地将其替换为 $(PROTOCOLS) 吗?
(不过,就我个人而言,我会坚持保罗的Makefile第一条规则:不要麻烦如果要编写便携式 makefile,请改用便携式 make。)

This appears similar to an issue with Fortran programming and make, involving the files generated when compiling a module. (Not relevant, other than that is where I picked up how to do this.)

What you want is have make compare the timestamp of protolist.o to the timestamp of protolist.c, which remains 'old', and make the decision to run the recipe for protolist.c, depending on the timestamp of, well, a timestamp file, which gets updated each time the recipe is run.
In order to make this work, you have to link the two together with an empty rule.

protolist.o: protolist.c
    [...]

protolist.c: protolist.c.time ;

protolist.c.time: $(PROTOCOLS) Makefile src/genmodtable.sh
    $(SHELL) $(srcdir)/src/genmodtable.sh \
        protolist.c $(filter-out %Makefile %genmodtable.sh, $^)
    touch protolist.c.time

In my own makefiles, I have to declare the timestamp files as prerequisites of the special target .PRECIOUS, to prevent make from deleting them, but I'm using pattern rules; I'm not 100% sure, but I think this isn't necessary when using explicit rules, like here.

To avoid the $(filter-out ...) construct, can you not simply replace it with $(PROTOCOLS)?
(Although, personally, I would stick to Paul's First Rule of Makefiles: Don't hassle with writing portable makefiles, use a portable make instead.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文