Does anybody know that the cause for this behavior might be?
I found the cause: If I replace "mod" by "o" everywhere in my
Makefile, the problem disappears. However, I don't quite understand
why.
The only plausible explanation is that the timestamps of the existing .mod
files are not updated when the original sources are rebuilt. I presume that extends only as long as the module interface is unchanged -- i.e. no functions or subroutines are added or removed, or modified in a way that affects their external interface, and similarly no module variables are added, removed, or changed in type.
I can see that it might be considered desirable to avoid updating .mod
files when nothing in them has actually changed, particularly in conjunction with module implementations stored in external libraries. To the best of my knowledge, however, there is no general standardization of even the existence of .mod
files, much less the circumstances under which they are created or updated. Your compiler may offer an option that forces them to be updated when their corresponding source is compiled; if so, that adding that option to your compile commands ought to resolve your issue.
Otherwise, the thing that your compiler does surely promise is that if you ask it to compile a source file to an object file, then on success, it will write a new object file. Moreover, although I would not necessarily have guessed that the same would be untrue of the .mod
files, it is important to understand that the latter normally describe the interfaces to your modules, not their implementations, so your main rule is semantically incorrect:
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
You need to rebuild if any of the implementations change, regardless of whether module interfaces change, and your rule does not adequately capture that requirement.
At this point I observe also that when you rebuild via that rule, you rebuild all the sources, making the per-source build rules pointless. If that's what you want, then a simpler solution would be to rewrite your while makefile to this:
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 {} +
There, the target is actually built from the specified prerequisites, and the build recipe is sufficient to build the target from those prerequisites. However, if any of the sources change, it will rebuild them all (similar to what your original makefile does).
The alternative is to build individual objects and then link them together in a separate step. Your original makefile seems to lean in that direction, but then it throws it away with the main rule. If you want to take that approach, then it becomes complicated by the facts that
- it really is the module interfaces on which the individual objects depend (in addition to their own sources), so expressing prerequisites in terms of other object files is incorrect in these cases;
- both the
.o
and .mod
files are built by the same process (i.e. it has multiple outputs);
- and apparently, that process uses different logic than
make
does to determine whether the .mod
files are out of date.
The multiple outputs issue is probably the hairiest one; you can find a discussion and alternative solutions of varying rigor in the Automake documentation (but not specific to Automake).
Here's a way you could approach that, inspired by the Automake docs but accounting for the peculiarity you discovered in your Fortran implementation:
# 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 {} +
This exhibits the correct dependencies:
- The main program depends (only) on all the objects.
- Each object depends on its own source and on the
.mod
files for those modules it uses.
It also accounts for the fact that the same compilation process generates both an object file and (where appropriate) a corresponding .mod
file, and it takes care of updating .mod
timestamps where that is needed to satisfy make
. It may occasionally cause files to be rebuilt when they didn't really need to be, because it will thwart any attempt by the compiler to avoid updating .mod
files' timestamps. But that should be on a one-time basis, not every subsequent build.