1

I encounter an error relating to implicit rule in make (3.81). The example codes are:

dongli:test02 dongli$ ls -R
Makefile a.F90    b.F90    dir

./dir:
a.t.F90

The dependencies among the codes are:

a.t.F90: a.F90
a.t.o: a.t.F90
b.o: b.F90
b: a.t.o b.o

That is a.F90 is intermediate code, and a.t.F90 will be updated when a.F90 is updated. My make process is:

Test 1 (All codes on position):

-------------------------------------------------------------
 Project: >>> test <<<
-------------------------------------------------------------
 Creating dependency a.t.o
-------------------------------------------------------------
-----> ./dir/a.t.F90
 Creating dependency b.o
-------------------------------------------------------------
-----> b.F90
 Creating target 'b'
 ---> b is created.
-------------------------------------------------------------
 Finished
-------------------------------------------------------------

Test 2 (touch 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

Test 3: (Run make again):

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
-------------------------------------------------------------

I know there is a bug in make about directory caching (see here), but in my case, dir/a.t.F90 exists all the time. Any idea? Thanks!

Update1:

I use make -d to capture the following information in test 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'.

Why ./dir/a.t.F90 is ignored when its prerequisite a.F90 is newer than it?

Update2:

I have put the example codes on gist.

Update3:

I found the following relating information:

If a target needs to be rebuilt, GNU make discards the file name found during the VPATH search for this target, and builds the file locally using the file name given in the makefile. If a target does not need to be rebuilt, GNU make uses the file name found during the VPATH search.

4

2 回答 2

2

您确实需要展示创建这些目标的规则。您已经提供了有关构建的许多方面的大量信息,但调试 make 问题的最关键方面之一是查看规则。

像这样的失败(第一次构建失败,第二次成功)几乎总是由于规则的行为不像你描述的那样。如果你告诉 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 不知道如何构建并期望始终存在)。如果没有更多地了解您的 makefile 以及规则是如何构建的,我们只能这么说。

编辑添加:

我不确定是否真的有必要使用这么多 eval 并在这里调用;通常人们似乎直接使用这些非常强大的工具,而更简单的工具也足够了。无论如何,您遇到的问题与我在上面的第一条评论中所怀疑的完全一样;你有这个规则:

%.t.F90: %.$(1)
        @echo " Processing templates in $$^"
        @echo $$(seperator)
        @cp $$< dir/$$@

请注意最后一行,而不是创建$@您正在创建dir/$@; 这正是我上面描述的情况。每当您的规则构建的东西不完全正确$@时,几乎可以 100% 确定该规则是错误的。你需要把它写成:

dir/%.t.F90: %.$(1)
        @echo " Processing templates in $$^"
        @echo $$(seperator)
        @cp $$< $$@

并且可能会进行更多更改以匹配该目标。

于 2013-07-22T15:19:49.513 回答
-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)

由 标记<

于 2013-07-23T07:24:57.207 回答