使隐式规则第一次失败但第二次成功

时间:2013-07-22 14:27:02

标签: makefile

我在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期间找到的文件名   搜索范围。

2 个答案:

答案 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)

标有<