Makefile 使忽略的前提条件不';不存在

Makefile 使忽略的前提条件不';不存在,makefile,gnu-make,Makefile,Gnu Make,make继续构建,并表示当我的依赖项文件表示对象依赖于已移动的头文件时,所有内容都是最新的 如果运行make-d捕获我看到的评估: Considering target file `../build/out/src/manager.o'. Looking for an implicit rule for `../build/out/src/manager.o'. No implicit rule found for `../build/out/src/manager.o'.

make
继续构建,并表示当我的依赖项文件表示对象依赖于已移动的头文件时,所有内容都是最新的

如果运行
make-d
捕获我看到的评估:

Considering target file `../build/out/src/manager.o'.
     Looking for an implicit rule for `../build/out/src/manager.o'.
     No implicit rule found for `../build/out/src/manager.o'.
      Pruning file `../product/build/config/product.conf'.
      Pruning file `../build/out/opt_cc.txt'.
      Considering target file `../mem/src/manager.c'.
       Looking for an implicit rule for `../mem/src/manager.c'.
       No implicit rule found for `../mem/src/manager.c'.
       Finished prerequisites of target file `../mem/src/manager.c'.
      No need to remake target `../mem/src/manager.c'.
      Pruning file `../mem/mem.h'.
     Finished prerequisites of target file `../build/out/src/manager.o'.
     Prerequisite `../product/build/config/product.conf' is older than target `../build/out/src/manager.o'.
     Prerequisite `../build/out/opt_cc.txt' is older than target `../build/out/src/manager.o'.
     Prerequisite `../mem/src/manager.c' is older than target `../build/out/src/manager.o'.
     Prerequisite `../mem/mem.h' of target `../build/out/src/manager.o' does not exist.
../build/out/src/manager.o'.
     Prerequisite `../mem/mem_in.h' is older than target `../build/out/src/manager.o'.
    No need to remake target `../build/out/src/manager.o'.
因此make知道该文件是需要的,并且不在那里,但不会尝试根据规则创建该文件,否则将失败

Prerequisite `../mem/mem.h' of target `../build/out/src/manager.o' does not exist.

这是为什么?我如何才能让make不忽略此规则?

很可能您已经实现了一种自动依赖项生成方法,该方法告诉make在不存在这些文件的情况下,通过在没有规则的情况下为该文件定义目标,从根本上忽略这些文件。当我有这个makefile时:

foo: foo.h ; @echo make $@ from $^
foo: foo.h ; @echo make $@ from $^
foo.h:
没有
foo.h
make告诉我:

$ make
make: **** No rule to make target 'foo.h', needed by 'foo'.  Stop.
但是,如果我有这个makefile:

foo: foo.h ; @echo make $@ from $^
foo: foo.h ; @echo make $@ from $^
foo.h:
现在,make非常高兴:

$ make
make foo from foo.h
这是许多自动依赖项生成实用程序所依赖的有文档记录的行为:如果查看生成的依赖项生成文件,您将看到每个头文件的一个空目标


其思想是,给定正确的依赖关系信息,在不修改其他源文件或头文件的情况下,决不能重命名或删除头文件,这将导致无论如何都要重建对象文件(因此下次正确地重新创建依赖关系信息).

我发现的修复方法是使用静态模式规则而不是模式规则。模式规则如下所示:

%.o : %.c
    *recipe here*
$(OBJECTS): %.o: %.c
    *recipe here*
静态模式规则仅适用于目标文件的显式列表,如下所示:

%.o : %.c
    *recipe here*
$(OBJECTS): %.o: %.c
    *recipe here*
其中变量
OBJECTS
在makefile的前面定义为目标文件列表(用空格分隔),例如:

OBJECTS := src/fileA.c src/fileB.c src/fileC.c
请注意,您可以使用各种
make
实用程序函数来构建目标文件列表。例如,
$(通配符模式)
$(addsuffix)
,等等

您没有显示makefile的相关部分,因此我不能确定这是否能解决您的问题。但是我得到了同样的症状,即
make
忽略不存在的先决条件,来自
make-d
的关于“先决条件不存在”的相同消息,但是
make
没有创建先决条件

请注意,
make
包含大约90个内置隐式规则,其中大多数是模式规则。因此,即使您的makefile没有模式规则,这仍然会影响您

我注意到一些事情:

  • 明确要求先决条件起作用。这表明
    make
    知道如何构建先决条件

  • 为特定文件添加显式目标语句(不使用模式规则)似乎可以解决问题。(当然,只针对这一个目标……为100个目标中的每一个制定规则是行不通的)

  • 在我的研究中,我不断遇到这样的说法,即如果有明确的目标与否,
    make
    的行为是如何不同的

  • 使用
    make-r
    关闭隐式规则数据库没有帮助

  • 我猜这之所以有效,是因为静态模式规则是整个目标列表的显式目标语句的一种形式

    对于我正在调查的特定情况,目标文件已经存在,并且构建目标实际上不需要(不存在)先决条件,它只在运行时需要。因此,
    make
    关于不需要构建先决条件来构建目标的说法可能是正确的。如果你只是要求建立目标,那么make会尽可能少地完成

    它看起来仍然像是
    make
    中的一个bug。但这可能只是我的错误理解,我不是专家

    更新:(2016年3月16日)。我目前的理解是
    make
    将这些必备文件视为中间文件,因此不关心在目标文件已经存在时创建它们
    Make
    将中间文件视为“二级公民”,它仅在创建“一级公民”(makefile中定义的明确目标)或命令行上作为
    Make
    参数请求的目标时才创建中间文件

    通过使用静态模式规则(而不是模式规则),这些文件现在被列为显式目标,因此不是中间文件,而是“第一类公民”,在必要时创建和更新


    顺便说一句,这也解释了为什么在没有先决条件的情况下使用
    .SECONDARY
    没有帮助。这样做可以防止删除中间文件,但它们仍然被视为中间文件,因此除非需要创建目标或目标,否则不会创建它们。

    我在代码库中对此问题研究了很长时间,但找不到与我的情况相匹配的任何原因(或解决方案)(不管我在这个主题上搜索了多少次)。@owler在“Update:(2016年3月16日)”附录中,提供了一个关于“使用
    .SECONDARY
    不带任何先决条件”语句实际问题的提示防止删除中间文件,但它们仍被视为中间文件,因此make不会创建它们,除非需要它们来创建目标。”

    实际上,“中间”文件还有一个额外的特性,它实际上导致了我遇到的问题

    以下是makefile的外观:

    .SECONDARY:
    
    x.exe: x.o
            $(RECIPESTEP1)
    
    x.o: x.c
            $(RECIPESTEP2)
    
    在我的例子中,x.o是没有被重建的目标(即使它被明确列为make goal x.exe的依赖项)。更重要的是(为了理解这个问题),x.exe已经存在

    “中间”目标的完整行为描述是,仅当需要“中间”目标来构建从属目标时,才会构建“中间”目标。如果必须重建“中间”目标的从属关系,则才会构建“中间”目标。在我的例子中,“x.c”文件