如何使用模块为 Fortran 程序创建联编文件

How to create a makefile for a Fortran program using modules

挑战在于创建一个包含模块列表的 makefile,并且不需要我整理优先级。例如,模块是

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

主程序是characterize.f08。错误信息是

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

主程序中的第一条语句是use mPrecisionDefinitionsmod precision definitions.f08中定义的模块。

以下基于 Creating a FORTRAN makefile 的 makefile 是:

# 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

对于初学者,我建议用下划线或类似的东西替换文件名中的所有空格。

空格几乎普遍用作分隔符,任何以类似

开头的程序
gfortran -c -o mod precision definitions.o mod precision definitions.f08

会将此行解释为“从源文件 precisiondefinitions.omodprecisiondefinitions.f08。虽然有很多方法可以做到,但随着自动化程度的提高,您必须跳得越来越多。

相比之下,这个效果很好:

gfortran -c -o mod_precision_definitions.o mod_precision_definitions.f08

我将使用此命令将所有空格更改为下划线:

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

如果这不起作用,请使用此命令:

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

接下来,我不会担心 .mod 个文件。当您编译模块时,它们会与目标文件一起生成。因此,虽然从技术上讲,某些使用模块的例程需要该模块的 .mod 文件,但您也可以在 Makefile 中声明它取决于目标文件本身。

话虽如此,这是我要使用的 Makefile(添加了一些假设的模块间依赖项):

# 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