Module 如何使用模块为Fortran程序创建makefile

Module 如何使用模块为Fortran程序创建makefile,module,makefile,fortran,gfortran,Module,Makefile,Fortran,Gfortran,面临的挑战是创建一个makefile,它包含一个模块列表,并且不需要我整理之前的关系。例如,模块是 mod allocations.f08 mod precision definitions.f08 mod unit values.f08 mod blocks.f08 mod shared.f08 mod parameters.f08 mod timers.f08 主程序是characterized.f08。错误消息是 致命错误:

面临的挑战是创建一个makefile,它包含一个模块列表,并且不需要我整理之前的关系。例如,模块是

mod allocations.f08     mod precision definitions.f08   mod unit values.f08
mod blocks.f08          mod shared.f08                  mod parameters.f08
mod timers.f08
主程序是
characterized.f08
。错误消息是

致命错误:无法打开模块文件“mprecisiondefinitions.mod”进行读取(1):没有此类文件或目录

主程序中的第一条语句是
use-mPrecisionDefinitions
,该模块在
mod precision definitions.f08
中定义

以下生成文件基于以下内容:

#编译器
FC:=/usr/local/bin/gfortran
#编译标志
FCFLAGS=-g-c-Wall-Wextra-Wconversion-Og-pedantic-fcheck=bounds-fmax errors=5
#链接标志
FLFLAGS=
#源文件和对象
SRCS=$(patsubst%.f08、%.o、$(通配符*.f08))
#程序名
程序=a.out
全部:$(程序)
$(程序):$(SRCS)
$(FC)$(FLFLAGS)-o$@$^
%.mod:%.f08
$(FC)$(FCFLAGS)-o$@$<
%.o:%.f08
$(FC)$(FCFLAGS)-o$@$<
清洁:
rm-f*.o*.mod

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

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

gfortran -c -o mod precision definitions.o mod precision definitions.f08
将此行解释为“从源文件
precision
definitions.o
mod
precision
definitions.f08
创建一个名为
mod
的对象文件。”。虽然有办法做到这一点,但随着自动化程度的提高,你必须跳出越来越多的障碍

相比之下,这种方法效果很好:

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(添加了一些假定的模块间依赖项):

#找到所有源文件,创建相应目标文件的列表
SRCS=$(通配符*.f08)
OBJS=$(patsubst%.f08,%.o,$(SRCS))
#mods同上(它们将在两个列表中)
MODS=$(通配符mod*.f08)
MOD_OBJS=$(patsubst%.f08,%.o,$(MODS))
#编译器/链接器设置
FC=gfortran
FLFLAGS=-g
FCFLAGS=-g-c-Wall-Wextra-Wconversion-Og-pedantic-fcheck=bounds-fmax errors=5
程序=特征化
PRG_OBJ=$(程序).o
#不带参数的make将使第一个目标找到。
默认值:$(程序)
#所有对象的编译器步骤
$(OBJS):%.o:%.f08
$(FC)$(FCFLAGS)-o$@$<
#链接器
$(程序):$(OBJS)
$(FC)$(FLFLAGS)-o$@$^
#如果某项工作不正常,请进行“make debug”调试
#显示每个变量包含的内容。
调试:
@echo“SRCS=$(SRCS)”
@echo“OBJS=$(OBJS)”
@echo“MODS=$(MODS)”
@echo“MOD_OBJS=$(MOD_OBJS)”
@echo“程序=$(程序)”
@回显“PRG_OBJ=$(PRG_OBJ)”
清洁:
rm-rf$(OBJS)$(PROGRAM)$(patsubst%.o、%.mod、$(mod_OBJS))
.PHONY:调试默认清除
#依赖关系
#主程序依赖于所有模块
$(PRG_OBJ):$(MOD_OBJS)
#块和分配取决于共享
mod_块.o mod_分配.o:mod_共享.o

我建议您避免使用
.f08
后缀。在每次语言修订时更改源代码文件的后缀是没有意义的。默认情况下,某些编译器(英特尔)会拒绝它。源表单文件的有效标准后缀是
.f90
。它不是指Fortran 90,而是指自由格式的源代码。这有点不幸,但事实就是这样。看@VladimirF:像往常一样,你的观点是正确的。与之相对应的是,在使用几种语言编程多年后,能够使用这种形式的乡村时间戳对项目进行排序是很有帮助的。这非常有效。很好的解释。您的模块相互依赖性示例简单明了。将空格转换为下划线的单行命令非常有用。由于您对将空格转换为下划线的单行命令发表了评论,我想通知您,我找到了使用
重命名
的更好方法,并相应地更新了答案。回答不错。我想指出的是,由于这里使用的是模式规则(%.o:%.f08),而不是后缀规则,所以包含.后缀的两行是不必要的。
for f in *.f08; do mv "$f" ${f// /_}; done
# 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