make重新编译源代码文件,即使它们没有更改。要重现此行为,我需要这样做:
在此示例中,在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与旧的变化有关。有人知道造成这种现象的原因吗?
答案 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似乎朝那个方向倾斜,但随后将其与主要规则抛弃了。如果您想采用这种方法,那么事实会变得复杂
.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”,问题就消失了。但是,我不太清楚为什么。