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.
为什么会这样,我怎样才能不忽视这条规则?
答案 0 :(得分:6)
您很可能已经实现了一种自动依赖关系生成方法,通过在没有规则的情况下为该文件定义目标,告诉make基本上忽略这些文件(如果它们不存在)。当我有这个makefile:
foo: foo.h ; @echo make $@ from $^
然后没有foo.h
告诉我:
$ make
make: **** No rule to make target 'foo.h', needed by 'foo'. Stop.
但是,如果我有这个 makefile:
foo: foo.h ; @echo make $@ from $^
foo.h:
现在make非常高兴:
$ make
make foo from foo.h
这是许多自动依赖关系生成实用程序依赖的文档化行为:如果查看生成的依赖关系makefile,您将看到每个头文件中的一个空目标。
这个想法是,给定正确的依赖信息,永远不应该有一种方法来重命名或删除头文件而不修改其他源或头文件,这将导致目标文件无论如何重建(因此正确地重新创建依赖性信息)下一次)。
答案 1 :(得分:3)
我发现的修复是使用静态模式规则而不是模式规则。模式规则如下所示:
%.o : %.c
*recipe here*
静态模式规则仅适用于目标文件的显式列表,如下所示:
$(OBJECTS): %.o: %.c
*recipe here*
其中变量OBJECTS
在makefile中先前定义为目标文件列表(以空格分隔),例如:
OBJECTS := src/fileA.c src/fileB.c src/fileC.c
请注意,您可以使用各种make
实用程序函数来构建目标文件列表。例如,$(wildcard pattern)
,$(addsuffix)
等
您没有显示makefile的相关部分,因此我无法确定这是否能解决您的问题。但是我得到make
忽略不存在的先决条件的相同症状,并且来自make -d
的关于“先决条件不存在”的相同消息但是make
没有创建先决条件。
请注意,make
包含大约90个内置隐式规则,其中大多数是模式规则。因此,即使你的makefile没有模式规则,这仍然会影响你。
我注意到了一些事情:
要求明确地使先决条件有效。这表明make
知道如何构建先决条件。
为特定文件添加显式目标语句(不使用模式规则)似乎可以解决问题。 (但当然只针对那个目标......为100个目标编写规则是不可行的。)
在我的研究中,如果有明确的目标,我会不断遇到关于make
行为如何不同的陈述。
使用make -r
关闭隐式规则数据库没有帮助。
我猜这可行的原因是静态模式规则是整个目标列表的显式目标语句形式。
对于我正在研究的特定情况,目标文件已经存在,并且实际上不需要(不存在的)先决条件来构建目标,它只在运行时需要。所以也许make
对于不需要构建先决条件以构建目标是正确的。如果您只是要求构建目标,那么make将尽可能地完成目标。
它似乎仍然是我不是make
中的错误。但这可能只是对我的误解,make
专家。
更新:( 2016年3月16日)。我目前的理解是make
将这些必备文件视为中间文件,因此无需创建目标文件已存在时的它们。 Make
将中间文件视为“二等公民”,它只在需要时创建“第一类公民”,它们是makefile中定义的显式目标,或者作为make
的参数请求的目标在命令行上。
通过使用静态模式规则(而不是模式规则),这些文件现在被列为显式目标,因此不是中间文件,而是“一等公民”在必要时创建和更新。
顺便说一句,这也解释了为什么在没有先决条件的情况下使用.SECONDARY
没有帮助。这样做可以防止中间文件被删除,但它们仍被视为中间文件,因此make
除非需要制作目标或目标,否则不会创建它们。
答案 2 :(得分:0)
我在我的代码库中解决这个问题已经有一段时间了,但找不到任何符合我情况的原因(或解决方案)(无论我对该主题进行了多少次搜索)。 @owler,在“更新:(2016 年 3 月 16 日)”附录中,提示了语句“[使用 .SECONDARY
没有先决条件] 防止中间文件被删除,但它们仍然存在被视为中间体,因此除非需要它们来制定目标或目标,否则 make 不会创建它们。”
实际上是“中间”文件的另一个特征导致了我遇到的问题。
这是生成文件的样子:
.SECONDARY:
x.exe: x.o
$(RECIPESTEP1)
x.o: x.c
$(RECIPESTEP2)
就我而言,x.o 是未重建的目标(即使它明确列为 make 目标 x.exe 的依赖项)。更重要的是(为了理解问题),x.exe 确实已经存在。
“中级”目标的完整行为描述是“中级”目标将仅构建为依赖目标并且如果必须重建“中间”目标的依赖项。在我的例子中,'x.c' 文件已经存在并且没有依赖关系,所以 make 决定不需要重新构建 'x.c'。由于所有目标(包括“x.o”)都被标记为“中级”(由于 .SECONDARY:
目标没有依赖关系)并且由于不需要重新构建“xc”,因此 make 假定最多日期 'xo' 已经用于构建 'x.exe'(因为 'x.exe' 已经存在)。因此,make 不会(重新)构建 'x.o'。
最后,是@Owler 的评论和对 https://www.gnu.org/software/make/manual/html_node/Special-Targets.html 参考页面的(仔细)审查导致了解决方案的发现。
请注意,我提供了一个简化的 makefile,但在实际的 makefile 中,x.o 是根据基于 x.c 的隐式规则构建的 - 静态模式规则并没有解决我遇到的问题。
我的解决方案是删除 .SECONDARY:
目标。展望未来,计划是在必要时仅指定具有特定依赖项的 .SECONDARY:
。