4

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
dantopa
  • 616
  • 7
  • 19
  • 4
    I suggest you to avoid the `.f08` suffix. There is no point changing the suffix of source code files with every language revision. Some compilers (Intel) will refuse it by default. The effectively standard suffix for source form files is `.f90`. It does not mean Fortran 90, it means free-form source. It is a bit unfortunate, but that's how it is.See http://stackoverflow.com/questions/20269076/correct-suffix-for-fortran-2003-source-file-intel-fortran-compiler – Vladimir F Героям слава Feb 08 '16 at 09:30
  • 1
    @VladimirF: As usual, you make a good point. A modest counterpoint is that after programming in a few languages for many years it is helpful to be able to sort projects with this form of a rustic timestamp. – dantopa Feb 08 '16 at 15:43

1 Answers1

12

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
chw21
  • 7,970
  • 1
  • 16
  • 31
  • This works great. Very good explanation. Your module inter-dependencies example is simple and clear. The one-line command to convert spaces to underscores is very helpful. – dantopa Feb 08 '16 at 16:09
  • 2
    Since you commented on the one-line command to convert spaces to underscores, I would like to inform you that I found a better way with `rename` and have updated the answer appropriately. – chw21 Oct 21 '18 at 22:27
  • 1
    Nice answer. I'd like to comment that the two lines containing .SUFFIXES are unnecessary since pattern rule (%.o: %.f08) rather than suffix rule is used here. – Jiaqi Li Nov 22 '18 at 18:00