GNU Make“删除中间文件”

31

我有以下规则

define compile_c
$(ECHO) "CC $<"
$(Q)$(CC) $(CFLAGS) -c -MD -o $@ $<
@# The following fixes the dependency file.
@# See http://make.paulandlesley.org/autodep.html for details.
@# Regex adjusted from the above to play better with Windows paths, etc.
@$(CP) $(@:.o=.d) $(@:.o=.P); \
  $(SED) -e 's/#.*//' -e 's/^.*:  *//' -e 's/ *\\$$//' \
      -e '/^$$/ d' -e 's/$$/ :/' < $(@:.o=.d) >> $(@:.o=.P); \
  $(RM) -f $(@:.o=.d)
endef

vpath %.c . $(TOP)
$(BUILD)/%.o: %.c $(BUILD)/%.pp
    $(call compile_c)

vpath %.c . $(TOP)

$(BUILD)/%.pp: %.c
    $(ECHO) "PreProcess $<"
    $(Q)$(CC) $(CFLAGS) -E -Wp,-C,-dD,-dI -o $@ $<

当编译完成后,GNU make会打印
Removing intermediate files...并删除所有的 .pp 文件,但我不希望这样。

为什么会这样?
该怎么停止它?


2
您正在使用的URL用于依赖项生成已过时,并且可能在某些时候消失。您应该使用正确的URL:http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/。 - MadScientist
4个回答

22

由于您正在使用GNU Make,因此您可以对Makefile进行以下调整:

.PRECIOUS: $(BUILD)/%.pp  # ADD THIS LINE
$(BUILD)/%.pp: %.c
    $(ECHO) "PreProcess $<"
    $(Q)$(CC) $(CFLAGS) -E -Wp,-C,-dD,-dI -o $@ $<

文档.PRECIOUS指令有如下说明:

依赖于 .PRECIOUS 的目标会受到以下特殊处理:如果在执行其命令期间,make 被中止或杀死,则不会删除该目标。

[...]

此外,如果该目标是中间文件,则不会像通常那样在不再需要它时被删除。

[...]

您还可以将隐式规则(例如‘%.o’)的目标模式列为特殊目标.PRECIOUS的先决条件文件,以保留由其目标模式与该文件名称匹配的规则创建的中间文件。

这样做的好处在于不会创建不必要的附加规则。同时,能够更清晰地了解您所要做的事情:保留可能昂贵而难以重新创建的宝贵中间文件。


9
个人而言,我会避免使用.PRECIOUS,除非这真的是你想要的。它绝不能被随意用作目标声明的替代方式,正如上面的答案所示。请仔细考虑文档中的内容:如果make被中断或打断,目标将不会被删除。如果你正在编译一个大文件并使用^C,这将中断make,并且也会中断你的编译器。一些编译器会清理半创建的目标,但有些则不会。由于半创建的目标具有更新的时间戳,make不会重新创建它。这可能是一个很难找到的问题。 - MadScientist
.SECONDARY比.PRECIOUS更好! - Nick Huang
3
我将这个留下来供后人参考,但在过去的几年里,我已经认同了应该更早地使用.SECONDARY而不是.PRECIOUS。当你正在积极调试某些内容并且希望在失败时保留部分输出时,.PRECIOUS仍然有其用处。 - Alex Reinking

20

我认为最好的解决方案是使用.SECONDARY特殊目标。只需添加这一行:

.SECONDARY:

引用手册:

.SECONDARY如果没有前置条件,会使所有目标都被视为次要的(也就是说,不会因为它被认为是中间文件而被删除)。

为什么这比将目标作为可丢弃目标的前提条件更好呢?那样会更加混乱,并且必须明确地为可能由模式规则生成的每组文件执行此操作。

为什么这比使用.PRECIOUS更好呢?这会导致文件即使在使用.DELETE_ON_ERROR时其命令失败时仍被保留。后者很重要,以避免失败的命令留下不良输出,然后被后续的make调用视为当前输出。在我看来,你总是想要.DELETE_ON_ERROR,但.PRECIOUS却破坏了它。


与“.PRECIOUS”不同,“.SECONDARY”不能与诸如“%.o”之类的隐式规则一起使用。 - syockit
2
@syockit 似乎$(%.o)这个.SECONDARY规则可以正常工作。 - CervEd

10

如果您搜索“gnu make intermediate files”,您将立即在GNU make手册的Implicit Rules章节中找到答案。它还告诉您如何避免这种情况:如果文件在makefile中被提及为目标或先决条件,则无法使其成为中间文件。

因此,只需将您的.pp文件作为某个规则的先决条件列出即可。它不必是一个被调用的规则。由于您没有在此处提供足够的makefile信息,因此我们无法提供完整的答案,但可以像以下内容一样:

all_pps: $(ALL_OBJECTS:.o=.pp)
假设您有一个变量ALL_OBJECTS,其中包含所有您的.o文件。

9
如果我搜索"gnu make intermediate files",我会发现这篇文章。这篇文章本身就保证了它在谷歌上的成功! - Drew
all_pps: $(ALL_OBJECTS:.o=.pp) 不起作用,因为只有最后一个 .pp 文件被考虑! - Nick Huang
也许我没有理解@NickHuang的评论,但就我理解的而言,它是不正确的。 - MadScientist
使用-save-temps呢?这样做会不会将编译器的调用次数减少一半呢? - Bob
我不确定-save-temps是什么意思(我猜这是一个编译器标志?绝对不是make的标志),它与问题或答案有什么关系呢? - MadScientist

2

以下是最终让PRECIOUS对我起作用的详细信息。您提供给PRECIOUS的模式必须与创建中间文件的规则中使用的模式完全相同。我想保存所有以moc_为前缀的文件。开始时,我使用了 .PRECIOUS: moc_% 但没有成功。然后我尝试了 .PRECIOUS: moc_%.cpp 这就解决了问题。


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