我在make
(3.81)中遇到与隐式规则有关的错误。示例代码为:
dongli:test02 dongli$ ls -R
Makefile a.F90 b.F90 dir
./dir:
a.t.F90
代码之间的依赖关系是:
a.t.F90: a.F90
a.t.o: a.t.F90
b.o: b.F90
b: a.t.o b.o
即a.F90
是中间代码,更新a.t.F90
时会更新a.F90
。我的make
流程是:
测试1 (位置上的所有代码):
-------------------------------------------------------------
Project: >>> test <<<
-------------------------------------------------------------
Creating dependency a.t.o
-------------------------------------------------------------
-----> ./dir/a.t.F90
Creating dependency b.o
-------------------------------------------------------------
-----> b.F90
Creating target 'b'
---> b is created.
-------------------------------------------------------------
Finished
-------------------------------------------------------------
测试2 (触摸a.F90
):
dongli:test02 dongli$ touch a.F90
dongli:test02 dongli$ make
-------------------------------------------------------------
Project: >>> test <<<
-------------------------------------------------------------
Processing templates in a.F90
-------------------------------------------------------------
Creating dependency a.t.o
-------------------------------------------------------------
-----> a.t.F90
gfortran: error: a.t.F90: No such file or directory
gfortran: fatal error: no input files
compilation terminated.
make: *** [a.t.o] Error 1
测试3 :(再次运行make
):
dongli:test02 dongli$ make
-------------------------------------------------------------
Project: >>> test <<<
-------------------------------------------------------------
Creating dependency a.t.o
-------------------------------------------------------------
-----> ./dir/a.t.F90
Creating dependency b.o
-------------------------------------------------------------
-----> b.F90
Creating target 'b'
---> b is created.
-------------------------------------------------------------
Finished
-------------------------------------------------------------
我知道make
中存在关于目录缓存的错误(请参阅here),但就我而言,dir/a.t.F90
始终存在。任何的想法?谢谢!
UPDATE1:
我使用make -d
来捕获测试2中的以下信息:
Finished prerequisites of target file `a.t.F90'.
Prerequisite `a.F90' is newer than target `a.t.F90'.
Must remake target `a.t.F90'.
Ignoring VPATH name `./dir/a.t.F90'.
...
Successfully remade target file `a.t.F90'.
Finished prerequisites of target file `a.t.o'.
Prerequisite `a.t.F90' of target `a.t.o' does not exist.
Must remake target `a.t.o'.
为什么./dir/a.t.F90
的先决条件a.F90
比它更新时会被忽略?
UPDATE2:
我已将示例代码放在gist上。
UPDATE3:
我找到了以下相关信息:
如果需要重建目标,GNU会丢弃找到的文件名 在VPATH搜索此目标期间,并在本地构建文件 使用makefile中给出的文件名。如果目标不需要 要重建,GNU make使用在VPATH期间找到的文件名 搜索范围。
答案 0 :(得分:2)
您确实需要显示创建这些目标的规则。您已经提供了很多关于构建的许多方面的信息,但调试中最重要的一个方面就是查看规则。
这样的失败(第一次构建失败而第二次成功失败)几乎总是由于规则不符合您的描述。如果你告诉make一个规则构建一个文件“foo”,通过创建类似foo : bar
的东西,但是你写的食谱实际上并不创建“foo”而是“bar / foo”,类似于:
foo : bar ; cp bar bar/foo
那是错的。这类问题的另一个常见原因是你定义了一个构建“foo.x”的规则,但它也构建了“foo.y”并且你没有告诉make它,但后来使用“foo.y”作为先决条件,那是行不通的。您必须定义一条规则,告诉make这两个文件是从配方的单个调用生成的,例如:
%.x %.y : %.z ; cp $< $*.x && cp $< $*.y
最后,您提到上面的VPATH,看起来您正在尝试使用VPATH查找生成的文件。那样不行。 VPATH只能 用于查找源文件(文件make不知道如何构建并期望始终存在)。如果没有详细了解你的文件以及如何构建规则,那就是我们可以说的全部内容。
编辑添加:
我不确定是否真的有必要使用这么多的评估并在这里打电话;通常人们似乎直接使用这些非常强大的工具,而更简单的工具就足够了。无论如何,你所遇到的问题正如我在上面的第一条评论中所怀疑的那样;你有这个规则:
%.t.F90: %.$(1)
@echo " Processing templates in $$^"
@echo $$(seperator)
@cp $$< dir/$$@
请注意最后一行,而不是创建$@
,而是创建dir/$@
;这正是我上面描述的情况。每当你有一个规则构建不完全$@
的东西时,几乎100%肯定规则是错误的。你需要把它写成:
dir/%.t.F90: %.$(1)
@echo " Processing templates in $$^"
@echo $$(seperator)
@cp $$< $$@
可能会有更多更改来匹配该目标。
答案 1 :(得分:-1)
我做了一个解决方法,我在隐式规则中插入了一些脚本,添加了代码中缺少的目录部分,因为VPATH
对此有一些限制。
%.o: %.$(1)
@echo " Creating dependency $$@"
@echo $$(seperator)
@TEMPLATE_PATTERN='.*\.t\.$(1)'; \ <
if [[ $$$$(dirname $$<) == '.' && '$$<' =~ $$$$TEMPLATE_PATTERN ]]; then \ <
SRC=$(PROJECT_ROOT)/.codemate/processed_codes/$$<; \ <
else \ <
SRC=$$<; \ <
fi; \ <
$(FC) -c $$$$SRC $(OPTIONS) $(FFLAGS) $(INCLUDES)
标有<
。