Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a makefile for a Fortran program using modules

The challenge is to create a makefile which takes a list of modules and does not require me to sort out precendence. For example, the modules are

mod allocations.f08     mod precision definitions.f08   mod unit values.f08
mod blocks.f08          mod shared.f08                  mod parameters.f08
mod timers.f08

The main program is characterize.f08. The error message is

Fatal Error: Can't open module file ‘mprecisiondefinitions.mod’ for reading at (1): No such file or directory

The first statement in the main program is use mPrecisionDefinitions, the module defined in mod precision definitions.f08.

The following makefile, based upon Creating a FORTRAN makefile, is:

# compiler
FC := /usr/local/bin/gfortran

# compile flags
FCFLAGS = -g -c -Wall -Wextra -Wconversion -Og -pedantic -fcheck=bounds -fmax-errors=5
# link flags
FLFLAGS =

# source files and objects
SRCS = $(patsubst %.f08, %.o, $(wildcard *.f08))

# program name
PROGRAM = a.out

all: $(PROGRAM)

$(PROGRAM): $(SRCS)
    $(FC) $(FLFLAGS) -o $@ $^

%.mod: %.f08
    $(FC) $(FCFLAGS) -o $@ $<

%.o: %.f08
    $(FC) $(FCFLAGS) -o $@ $<

clean:
    rm -f *.o *.mod
like image 671
dantopa Avatar asked Dec 15 '22 08:12

dantopa


1 Answers

For starters, I recommend to replace all spaces in your file names with underscores or something similar.

Spaces are almost universally used as separators, and any program that is started with something like

gfortran -c -o mod precision definitions.o mod precision definitions.f08

would interpret this line as 'create an object file called mod from the source files precision, definitions.o, mod, precision, and definitions.f08. And while there are ways to do it, with increasing automation, you have to jump more and more hoops.

In contrast, this works well:

gfortran -c -o mod_precision_definitions.o mod_precision_definitions.f08

I would use this command to change all the spaces into underscores:

rename 's/ /_/g' *.f08

If that doesn't work, use this command:

for f in *.f08; do mv "$f" ${f// /_}; done

Next, I wouldn't worry about .mod files. They get generated together with the object files when you compile a module. So while technically some routine that uses a module requires the .mod file for that module, you might as well claim in your Makefile that it depends on the object file itself.

So with that said, here's the Makefile I would use (with some assumed inter-module dependencies added):

# Find all source files, create a list of corresponding object files
SRCS=$(wildcard *.f08)
OBJS=$(patsubst %.f08,%.o,$(SRCS))

# Ditto for mods (They will be in both lists)
MODS=$(wildcard mod*.f08)
MOD_OBJS=$(patsubst %.f08,%.o,$(MODS))

# Compiler/Linker settings
FC = gfortran
FLFLAGS = -g
FCFLAGS = -g -c -Wall -Wextra -Wconversion -Og -pedantic -fcheck=bounds -fmax-errors=5
PROGRAM = characterize
PRG_OBJ = $(PROGRAM).o

# make without parameters will make first target found.
default : $(PROGRAM)

# Compiler steps for all objects
$(OBJS) : %.o : %.f08
    $(FC) $(FCFLAGS) -o $@ $<

# Linker
$(PROGRAM) : $(OBJS)
    $(FC) $(FLFLAGS) -o $@ $^

# If something doesn't work right, have a 'make debug' to 
# show what each variable contains.
debug:
    @echo "SRCS = $(SRCS)"
    @echo "OBJS = $(OBJS)"
    @echo "MODS = $(MODS)"
    @echo "MOD_OBJS = $(MOD_OBJS)"
    @echo "PROGRAM = $(PROGRAM)"
    @echo "PRG_OBJ = $(PRG_OBJ)"

clean:
    rm -rf $(OBJS) $(PROGRAM) $(patsubst %.o,%.mod,$(MOD_OBJS))

.PHONY: debug default clean

# Dependencies

# Main program depends on all modules
$(PRG_OBJ) : $(MOD_OBJS)

# Blocks and allocations depends on shared
mod_blocks.o mod_allocations.o : mod_shared.o
like image 142
chw21 Avatar answered Mar 16 '23 01:03

chw21