Wednesday 2 July 2014

The Fortran makefile dependency problem

For a project comprising of C/C++ code and header files, to simply compile once there is often no need for dependencies. Assuming that none of the header files are generated as part of the build process, it doesn't matter which order the source files are compiled in.

When developing a piece of code it is inefficient to recompile all the source files when a file has changed. Instead just the files which depend on those changes need to be recompiled. For example, when modifying a single C file only that file need be recompiled, or in the case of modifying a header file, all source files which include the header should be recompiled.

For a while standalone tools such as makedepend were used to generate these dependencies, but these have largely been superceded by the compilers themselves, commonly via a '-M' flag. This has great advantages, not least because the compiler itself knows best how to pre-process the file and which defines are internally set. A typical setup would therefore compile all files and then generate dependencies during the initial make. Subsequent makes include those dependencies and only recompiles things that have changed or are newly created, whilst of course also updating any dependencies accordingly.


There is a problem if one attempts to apply such a set-up to a Fortran project, namely F90 module files. Modules are similar to C header files, except that they themselves are source code which must be compiled before they can be used. For a small project one can of course write by hand that file A generates module M which is needed by files B and C. However, for larger projects, where modules are including other modules, which include other modules etc. this quickly becomes complicated. Some Fortran compilers (eg. gfortran) are able to generate dependencies via a '-M' option, but this is of little help since it can't be done until the relevant modules are available, a classic chicken and egg situation.

So unlike C, with Fortran the order in which source files should be compiled matters, and therefore dependencies must be generated before any compilation is done. This has unsurprisingly resulted in a whole series of tools designed to do this, sfmakedepend is the first that google turns up. In truth, many of these tools are actually more complicated than they need be since they often attempt to deal with Fortran and CPP include directives. These could be handled in the same way as C include directives, but of course it has the advantage that one does not need to generate separately module and include dependencies.

In conclusion, with Fortran one needs to generate at least module dependencies for all source files, and then include those dependencies before attempting to compile any source code.

It should be mentioned that for a Fortran project not making use of F90 module files this problem of course does not exist.

Tuesday 1 July 2014

EKOPath dependency generation bug

Most C/C++ compilers support dependency generation, often through the -M series of flags. For some reason the two version of EKOPath I've installed (5.0.1 and 5.0.5) contain a bug such that:

> pathCC -M test.cpp
psclang: error: unknown argument: '-Eonly'

The solution is to instruct the compiler to pre-process only and pass the -M option through to the preprocessor, i.e.:

> pathCC -E -Wp,-M test.cpp
test.o: test.cpp test.h