使重新编译未更改的文件

时间:2019-05-13 12:04:32

标签: makefile fortran recompile

make重新编译源代码文件,即使它们没有更改。要重现此行为,我需要这样做:

  1. 清理干净,只剩下* .90个文件
  2. 制作
  3. 保存* .f90文件之一,例如“ touch bands.f90”
  4. make:bands.f90已重新编译,这是正确的,因为它已更改
  5. make:bands.f90再次重新编译,这是不正确的,因为未触摸bands.f90

在此示例中,在4.之后,将在每次调用时重新编译bands.f90文件。如果我另外更改了任何其他源代码文件,则该行为也适用于该文件。因此,一段时间后,我最终重新编译了所有源代码。我可以通过调用make clean来部分解决此问题,这会重置循环。但这不是永久性的解决方法。

下面您将看到上面五个步骤的输出:

1: find . ! -name 'Makefile' -a ! -name '*.f90' -type f -exec rm -f {} +

2: [triggered by changes in const.f90]
   mpifort -c const.f90

   [triggered by changes in system.f90 const.mod]
   mpifort -c system.f90

   [triggered by changes in io.f90 system.mod const.mod]
   mpifort -c io.f90

   [triggered by changes in parallel.f90]
   mpifort -c parallel.f90

   [triggered by changes in bands.f90 system.mod io.mod const.mod parallel.mod]
   mpifort -c bands.f90

   [triggered by changes in polmob.f90 io.mod system.mod bands.mod parallel.mod]
   mpifort -o polmob polmob.f90 io.f90 system.f90 bands.f90 parallel.f90

3: "no output"

4: [triggered by changes in bands.f90]
   mpifort -c bands.f90

5: [triggered by changes in bands.f90]
   mpifort -c bands.f90

在第5步中,make应该实际上说没有要编译的东西。但是据说bands.f90有所更改,因此需要重新编译。

这是我的Makefile:

polmob: polmob.f90 io.mod system.mod bands.mod parallel.mod
    @echo [triggered by changes in $?]
    mpifort -o polmob polmob.f90 io.f90 system.f90 bands.f90 parallel.f90

io.mod: io.f90 system.mod const.mod
    @echo [triggered by changes in $?]
    mpifort -c io.f90

system.mod: system.f90 const.mod
    @echo [triggered by changes in $?]
    mpifort -c system.f90

bands.mod: bands.f90 system.mod io.mod const.mod parallel.mod
    @echo [triggered by changes in $?]
    mpifort -c bands.f90

const.mod: const.f90
    @echo [triggered by changes in $?]
    mpifort -c const.f90

parallel.mod: parallel.f90
    @echo [triggered by changes in $?]
    mpifort -c parallel.f90

clean:
    find . ! -name 'Makefile' -a ! -name '*.f90' -type f -exec rm -f {} +

标志$?告诉我,重新编译是由特定.f90文件中的更改触发的。因此,make与旧的变化有关。有人知道造成这种现象的原因吗?

2 个答案:

答案 0 :(得分:1)

  

有人知道造成这种现象的原因吗?

  

我找到了原因:如果我在各处都用“ o”替换“ mod”   Makefile,问题消失了。但是,我不太了解   为什么。

唯一合理的解释是,在重建原始源时,不会更新现有.mod文件的时间戳。我认为只有在模块接口不变的情况下才进行扩展-即,不会添加或删除或修改任何影响其外部接口的函数或子例程,并且类似地,也不会添加,删除或更改类型的模块变量

我可以看到,在实际上没有任何更改的情况下,避免更新.mod文件是可取的,尤其是与存储在外部库中的模块实现结合使用时。据我所知,.mod文件的存在甚至没有普遍的标准化,更不用说创建或更新它们的情况了。您的编译器可能提供一个选项,可以在编译相应的源时强制更新它们。如果是这样,在您的编译命令中添加该选项应该可以解决您的问题。

否则,编译器肯定会做出的承诺是,如果您要求编译器将源文件编译为目标文件,则编译成功后,它将编写一个新的目标文件。而且,尽管我不一定会猜到.mod文件是不正确的,但重要的是要了解后者通常描述模块的接口,不是其实现,因此您的主要规则在语义上是错误的:

polmob: polmob.f90 io.mod system.mod bands.mod parallel.mod
    @echo [triggered by changes in $?]
    mpifort -o polmob polmob.f90 io.f90 system.f90 bands.f90 parallel.f90

如果实现发生任何变化,则需要重建,而不管模块接口是否发生变化,并且您的规则不能充分满足该要求。

在这一点上,我还观察到,当您通过该规则进行重建时,您将重建 all 所有源,从而使每个源的构建规则毫无意义。如果这就是您想要的,那么一个更简单的解决方案是将while makefile重写为此:

SOURCES = polmob.f90 io.f90 system.f90 bands.f90 parallel.f90

polmob: $(SOURCES)
    @echo [triggered by changes in $?]
    mpifort -o $@ $(SOURCES)

clean:
    find . ! -name 'Makefile' -a ! -name '*.f90' -type f -exec rm -f {} +

在那里,实际上是根据指定的先决条件构建目标的,并且构建配方足以根据这些先决条件构建目标。但是,如果任何源发生更改,它将全部重建它们(类似于原始makefile所做的事情。)

另一种方法是构建单个对象,然后在单独的步骤中将它们链接在一起。您最初的makefile似乎朝那个方向倾斜,但随后将其与主要规则抛弃了。如果您想采用这种方法,那么事实会变得复杂

  • 确实是各个对象(除了它们自己的源)所依赖的模块 interfaces ,因此在这些情况下用其他对象文件表达前提条件是不正确的;
  • .o.mod文件都是通过相同的过程构建的(即,它具有多个输出);
  • 显然,该过程使用与make不同的逻辑来确定.mod文件是否过时。

多重输出问题可能是最毛的问题;您可以找到各种in the Automake documentation(但不是特定于Automake)的严格讨论和替代解决方案。

这是一种受Automake文档启发的方法,但是考虑到您在Fortran实施中发现的特殊性:

# All the object files contributing to the program:
OBJECTS = bands.o const.o io.o parallel.o polmob.o system.o

# Link all the objects together to form the final program
# (.mod files are typically not needed for this step)
polmob: $(OBJECTS)
    mpifort -o $@ $(OBJECTS)

# Rules for building the objects

bands.o : bands.f90 const.mod io.mod parallel.mod system.mod
    mpifort -c bands.f90 -o $@

const.o : const.f90
    mpifort -c const.f90 -o $@

io.o : io.f90 const.mod system.mod
    mpifort -c io.f90 -o $@

parallel.o : parallel.f90
    mpifort -c parallel.f90 -o $@

polmob.o : polmob.f90 bands.mod const.mod io.mod parallel.mod system.mod
    mpifort -c polmob.f90 -o $@

system.o : system.f90 const.mod
    mpifort -c system.f90 -o $@

# Rules for ensuring that .mod files are (re)created when needed, and
# that their timestamps do not fall behind those of their corresponding
# sources

bands.mod : bands.o
    @if test -f $@; then touch $@; else \
      rm -f bands.o; \
      $(MAKE) bands.o; \
    fi

const.mod : const.o
    @if test -f $@; then touch $@; else \
      rm -f const.o; \
      $(MAKE) const.o; \
    fi

io.mod : io.o
    @if test -f $@; then touch $@; else \
      rm -f io.o; \
      $(MAKE) io.o; \
    fi

parallel.mod : parallel.o
    @if test -f $@; then touch $@; else \
      rm -f parallel.o; \
      $(MAKE) parallel.o; \
    fi

system.mod : system.o
    @if test -f $@; then touch $@; else \
      rm -f system.o; \
      $(MAKE) system.o; \
    fi

####

clean:
    find . ! -name 'Makefile' -a ! -name '*.f90' -type f -exec rm -f {} +

这显示了正确的依赖性:

  • 主程序(仅)取决于所有对象。
  • 每个对象都取决于其自身的来源以及所使用的模块的.mod文件。

这也说明了一个事实,即同一编译过程既生成目标文件,又生成相应的.mod文件,并负责更新.mod时间戳记。满足make。有时可能会导致在不需要时重新构建文件,因为这会阻止编译器为避免更新.mod文件的时间戳所做的任何尝试。但这应该是一次性的,而不是以后的所有构建。

答案 1 :(得分:0)

我找到了原因:如果我在Makefile中的任何地方用“ o”替换“ mod”,问题就消失了。但是,我不太清楚为什么。