Search code examples
makefilefortrandependenciesgnu-makegfortran

Automatic dependency detection not working in GFortran


I the GCC Wiki it is stated that support for auto-detection of dependencies has been available since version 4.6:

Support the generation of Makefile dependencies via the -M... flags of GCC; you may need to specify additionally the -cpp option. The dependencies take modules, Fortran's include, and CPP's #include into account. Note: Using -M for the module path is no longer supported, use -J instead.

In my program I have two Fortran files: module_1.f08 and main.f08, where main uses module_1. I am using the following command to try to auto-detect dependencies of main:

gfortran -cpp -M main.f08

If module_1 has been already compiled, the command above returns a list of dependencies as expected, though if module_1 has not been compiled yet, I get an error message instead saying that module_1.mod does not exist.

The way I'm seeing this is that every time a new module is added to the code, it has to be compiled separately before running make all (or we might run make all before using the module in any other file, then use the module and compile again) or else any dependency of it might be compiled before the module itself and a compilation error will be returned.

Another thing is that dependency files have to be created gradually and one-by-one as the project grows, and if .mod files and dependency files got deleted at some point (with a make clean command for example), there will be no way to generate dependency files all at once using the auto-detection feature.

Is there a way to get around these limitations? Is there a way for auto-detection to work even if .mod files do not exist yet?


Solution

  • To start with, you need to add snippets to your Makefile to actually use the dependency generation feature. Additionally, you can use the -MD option to generate dependency files automatically for each target, so you don't need a special target to regenerate your dependencies. For an example project like yours above with a main.f90 that uses a module defined in mod1.f90 a simple Makefile using dependencies could look like:

    FC := gfortran
    FFLAGS := -O2 -g
    LIBS := # Needed libs like -lopenblas
    SRCS := mod1.f90 main.f90
    OBJS := ${SRCS:f90=o}
    DEPS := ${OBJS:o=d}
    
    myprog: $(OBJS)
        $(FC) $(FFLAGS) -o $@ $^ $(LIBS)
    
    .PHONY: clean
    clean:
        -rm -f $(OBJS) *.mod
    
    -include $(DEPS)
    
    %.o: %.f90 
        $(FC) $(FFLAGS) -cpp -MD -c -o $@ $<
    

    When you run make you'll see that it generates files main.d and mod1.d containing the dependencies for the corresponding source file.

    A (minor?) problem here is that your SRCS variable containing your list of source files must be listed in an order that allows the files to be compiled from left to right before you have any .d files. So the dependency stuff as it's done here doesn't help with ordering a build before the .d files have been generated. (Thus I'd recommend distributing the .d files as part of the source package.)