Fortran compilation dependency of modules and INCLUDE statement with make

51 Views Asked by At

I am compiling Fortran sources with MinGW and make on Windows.

Source file extensions are .f and .for - the .for are ones that are modules (some .for files even contain multiple modules).

I had a generic makefile ; it basically was

# Source directories
dirs := . srkf

# Executable to create
Executable = D:\Executables\a.exe
# -------------------------------------------------------

# Obj dir
Objets_dir = ../obj

VPATH = $(dirs) $(Objets_dir)

# Creation of .for list
Sourmod := $(foreach dir,$(dirs),$(wildcard $(dir)/*.for))

# Creation of .f list
Sources := $(foreach dir,$(dirs),$(wildcard $(dir)/*.f))

# Obj list
Objmod = $(patsubst %.for,%.o,$(Sourmod))
Objets = $(patsubst %.f,%.o,$(Sources))

# Full path to .o
TempObjets = $(addprefix $(Objets_dir)/, $(notdir $(Objmod) $(Objets)))

    
# Comp options
cpl = gfortran
cpl_opt = -ffpe-trap=invalid,zero,overflow -O3 -Wall
lnk = gfortran
lnk_opt = 

# Compilation
$(Objets_dir)/%.o:%.for
    $(cpl) -J$(Objets_dir) $(cpl_opt) -c $< -o $(Objets_dir)\$(notdir $@)
$(Objets_dir)/%.o:%.f
    $(cpl) -I$(Objets_dir) $(cpl_opt) -c $< -o $(Objets_dir)\$(notdir $@)

# Link
$(Executable): $(TempObjets)
    $(lnk) -o $@ $^ $(lnk_opt)

clean:
    @-rm -rf $(Objets_dir) $(Executable)

Modules are compiled first, but :

  • editing and updating a .for file does not lead to .f files using a module contained in said .for file to be recompiled, and
  • there is a small part of the project where due to external constraints, I will be required to use some (elementary) include statements (and not modules, although i will still use modules everywhere else), and the same kind of dependency problem arises. If I have a foo.f file with an include 'bar.inc' somewhere, then modifying the bar.inc file and compiling the code does not lead to foo.f being recompiled.

This is obviously problematic. How would you this makefile, so that BOTH behaviors / kind of dependencies are taken into account ?

Edit : it turns out the following solution, which has been provided to me, solves issues in both cases :

# Source directories
dirs := . srkf

# Executable to create
Executable = D:\Executables\a.exe
# -------------------------------------------------------

# Obj dir
Objets_dir ?= ../obj

VPATH = $(dirs) $(Objets_dir)

# Creation of .for list
Sourmod := $(foreach dir,$(dirs),$(wildcard $(dir)/*.for))

# Creation of .f list
Sources := $(foreach dir,$(dirs),$(wildcard $(dir)/*.f))

# Obj list
Objmod = $(patsubst %.for,%.o,$(Sourmod))
Objets = $(patsubst %.f,%.o,$(Sources))

# Full path to .o
TempObjets = $(addprefix $(Objets_dir)/, $(notdir $(Objmod) $(Objets)))
DEPENDS = $(patsubst %.o,%.d,$(TempObjets))

# Comp options
cpl = gfortran
FFLAGS = -ffpe-trap=invalid,zero,overflow -O3 -Wall
lnk = gfortran
lnk_opt = 

all: $(Executable)

# Compilation
$(Objets_dir)/%.o:%.for
    $(cpl) -J$(Objets_dir) $(FFLAGS) -c $< -o $@

$(Objets_dir)/%.o:%.f
    $(cpl) -I$(Objets_dir) $(FFLAGS) -c $< -o $@

$(Objets_dir)/%.d: %.for
    @-(echo -n $(Objets_dir)/;$(cpl) -cpp -MM -J$(Objets_dir) -fsyntax-only $(FFLAGS) -c $<) > $@

$(Objets_dir)/%.d: %.f
    @-(echo -n $(Objets_dir)/;$(cpl) -cpp -MM -I$(Objets_dir) -fsyntax-only $(FFLAGS) -c $<) > $@

-include $(DEPENDS)

# Link
$(Executable): $(TempObjets)
    $(lnk) $(lnk_opt) -o $@ $^

# Clean
clean:
    @-rm -rf $(Objets_dir)/* $(Executable)

#all:
#   @echo $(value Sources)
#   @echo $(value Objets)
#   @echo $(value TempObjets)

This indeed works both for includes (modifying the bar.inc file and compiling the code does now lead to foo.f being recompiled) as well as for modules.

gfortran (or make ?) seems actually quite smart. In the case of modules for example, if you edit and save a module, and then ask for a compilaton, it will (of course) recompile the module, but it will recompile other sources that depend on it ONLY if the resulting .mod file differs. I sure didn't expect that it would be this smart (I expected i to trigger a new compilation of dependent files as long as one of the upstream file was recompiled).

1

There are 1 best solutions below

6
MadScientist On

If you want all the Fortran (.f) files to be rebuilt whenever any of the module (.for) files is rebuilt, just make these changes to your makefile:

# Obj target lists
Objmod = $(patsubst %.for,$(Objets_dir)/%.o,$(notdir $(Sourmod)))
Objets = $(patsubst %.f,$(Objets_dir)/%.o,$(notdir $(Sources)))

# All objects
TempObjets = $(Objmod) $(Objets)

# Make sure all .f objects are rebuilt after any .for objects are built
$(Objets) : $(Objmod)