Matthew West

Fortran 90 Module Dependencies

The dependency structure in Fortran 90 is somewhat complex and compiler-dependent. The model assumed here is the one used by gfortran (version 4.3.2 at the time of writing).

The basic model is like C with source *.c and header *.h files, with source files named *.f90 that contain the actual code and module (header) files named *.mod that specify subroutine interfaces, derived types, and similar information.

The main difference from C is that the .mod files are auto-generated by the compiler from the source files and they are compiler dependent (that is, a Fortran compiler can only use module files produced by that specific compiler). If a.f90 contains the statement module a then compiling a.f90 will produce both a.o and the module definition file a.mod.

As of gcc version 4.3.0, gfortran will not change the timestamp on a.mod when compiling a.f90 unless the contents of a.mod file will actually change. This was done to fix bug 31587 which pointed out that unconditionally updating the timestamp on the .mod files produces excessive recompilations by make.

Unfortunately, this change to gfortran does not fit well with make's view of the world. We now have a situation where a.mod depends on a.f90, but a change to a.f90 may not produce an updated version of a.mod. As pointed out by Brian Dessent, this means we can't write a make rule for the .mod that doesn't violate Paul Smith's Rule 2. There seem to be three ways to deal with this:

  1. Use a build-system other than make that maintains its own database of dependency status (e.g. SCons).
  2. As suggested by FX Coudert we can do:
    a.o: a.f90
    	gfortran -c $<
    
    a.mod: a.f90 a.o
    	@true
    
    b.o: b.f90 a.mod
    	gfortran -c $<
    
    This has the advantage of not recompiling unnecessarily, but if the .mod file is missing then make will be unable to build at all.
  3. We can unconditionally touch the a.mod file every time we compile a.f90. This frequently results in excessive recompilation (the problem that bug 31587 was addressing), but at least it means that the build will always succeed and be correct.

I have used the third method successfully in PartMC version 1.1.0. To actually implement the third method in practice there are still a few issues to deal with, as follows.

Update 2009-07-10: As of PartMC version 1.2.0 I have switched to using CMake as the primary build-system, which does its own dependency resolution and correctly builds Fortran 90 modules automatically.

1. How to express to make the full directed acyclic graph of dependencies

For myfile.f90 containing the statements module providemod and use depmod, compiling myfile.f90 produces myfile.o and providemod.mod and the compile needs the file depmod.mod. The dependencies in make syntax are thus:

myfile.o: myfile.f90 depmod.mod
providemod.mod: myfile.f90 depmod.mod

These dependencies can be autogenerated by the f90_mod_deps.py python program from PartMC version 1.1.0.

2. How to express to make the fact that compiling produces several files simultaneously

The basic structure of makefiles has a single command producing a single output file. However, compiling the Fortran 90 source-file myfile.f90 containing the line module providemod will produce myfile.o and providemod.mod in a single pass. While we could just list two make targets for the .o and .mod files, this could result in make compiling myfile.f90 twice, once for each target.

Instead, we really want to indicate that the single compile command generates two files. While make cannot do this in general, GNU make can express this type of information with pattern rules. In make syntax we can write:

%.o %.mod: %.f90
	gfortran -c -o $@ $<

This says that myfile.o and myfile.mod both depend on myfile.f90 and are both produced by a single invocation of gfortran.

To take advantage of this feature of GNU make it is necessary to have only one module definition per source-file, and for the module name to be some simple variation on the source-file name.

A practical system

A convention that works well in practice is the following. Choose a prefix to indicate module names in the current project, such as mpp for my project prefix. Then each source-file myfile.f90 can contain at most one module definition that must be named mpp_myfile. We can now use the f90_mod_deps.py program from PartMC version 1.1.0 to generate the dependencies automatically with:

f90_mod_deps.py --output src/myfile.deps --dep-re "(mpp_.*)" \
      --dep-template "src/\1.mod" --mod-re "(.*)" \
      --mod-template "src/\1.mod" src/myfile.f90

This example is assuming that all source code is in the src subdirectory. In the main Makefile we should now include the dependencies and list the compile command with:

-include src/myfile.deps
src/%.o src/mpp_%.mod: src/%.f90
        gfortran -c -o %(patsubst %.f90,%.o,%<) %<
        touch %(patsubst src/%.f90,src/mpp_%.mod,%<)

Note that we can't use the -o $@ automatic variable for the target name, as it might refer to either the .o or .mod file.

We can also make src/%.deps a dependency and include a rule to generate the dependencies automatically. For an example of how to do this see the PartMC version 1.1.0 Makefile.