寻找最佳的多线程Fortran项目带模块的makefile

3
我将所有的代码放在模块中,每个源文件一个模块(除了在tests.f90文件中包含最小程序)。源文件和模块的名称相同,给出等效的名称,例如:src/computes.f90build/computes.obuild/computes.mod。使用use语句将模块链接起来。以下是本项目最好的makefile,但存在一个主要问题,即文件被无限重新考虑。
想法:可以使用-fsyntax-only快速编译只有.mod文件。当所有.mod文件存在时,.o文件没有内部依赖关系,可以按任何顺序编译,简化多线程编译。
当源文件被编译时,是否使用gfortran -fsyntax-only,只有在更改时才更新模块文件,而不管相应的对象文件是否已更新。因此,可以具有比相应的.f90文件更旧的.mod文件。
如果更新file.f90,则应更新相应的file.o文件和可能的file.mod文件。如果更新file.mod,则应使用gfortran -fsyntax-only file2.f90检查依赖于file.mod的file2.mod。只有当更新了file2.mod时,才应编译file2.o(这是耗时的步骤,否则应避免。这是否正确?)。
实现和问题:我在下面的makefile中实现了这些原则。但是,问题出现在(预期的)情况下,即更新了file.mod但未更新file2.mod的情况下。然后,make会一遍又一遍地运行gfortran -fsyntax-only file2.f90,因为先决条件比没有(也不应该)更新的目标老。
我能做什么?是否可以仅在替换file.mod时(即创建的时间)触发依赖项file2.mod,但是文件本身只要考虑最新的touch(例如最新修改的时间)即可?我也欢迎为不同的方法提出建议。
B = build
S = src
F = gfortran
f = -J$B -I$B 
P = program 

modfile_names = constypes computes systems tests

obj = $(addprefix $B/, $(modfile_names:=.o))   

vpath %.f90 $S

all:
    make -j4 $P

$P:$(obj)
    $F $f $^ -o $@

$B/%.o:%.f90 $B/%.mod
    $F $f -c $< -o $@

$B/%.mod:
    $F $f -fsyntax-only $S/$(notdir ${@:.mod=.f90}) 

$B/tests.mod: $B/constypes.mod $B/computes.mod $B/systems.mod
$B/computes.mod $B/systems.mod: $B/constypes.mod

.phony:clear
clear: 
    rm $B/* $P

模块重新编译级联真的是一个大问题吗?我有数百个模块的项目,它并没有特别困扰我。个人认为,在尝试强制构建系统之前,应该考虑将实现拆分成子模块-考虑一下如果您曾经更改编译器会发生什么。 - IanH
我不明白你是如何在没有使用“-fsyntax-only”的情况下实现模块编译级联的?这本身并不是一个大问题,但我想找到一个干净的解决方案来应用于一个更大的项目。我没有子模块的经验,这也意味着更改源代码的可能性更大,但这是可行的。 - Jonatan Öström
@IanH 关于可能更换编译器的问题,你说得很有道理。 - Jonatan Öström
1个回答

0

我的代码结构完全相同。仅当源文件被修改时,.o文件才会更新,但.mod文件可以更旧。

这是Makefile:

# Compiler options
FC  := $(F90) -cpp
FFLAGS  := -fdefault-real-8 -fdefault-integer-8 -Wall -Wtabs -Ofast -fcheck=all -ffree-line-length-none -pthread

# Define directories
OOP_DIR :=  ../oop
MOD_DIR :=  ../build
vortZ2D_DIR := ..

# Define file extensions
.SUFFIXES: .f90 .o .mod

# Targets (objects)
OBJ  = $(MOD_DIR)/fft.o $(MOD_DIR)/grid.o $(MOD_DIR)/geom.o $(MOD_DIR)/body.o $(MOD_DIR)/fluid.o
OBJ1 = $(MOD_DIR)/vortZ2D.o
TAR1 = vortZ2D

# Build rules
all: runner | $(MOD_DIR)

$(MOD_DIR):
    mkdir -p $(MOD_DIR)

$(MOD_DIR)/%.o: $(OOP_DIR)/%.f90 | $(MOD_DIR)
    $(FC) $(FFLAGS) -c $^ -o $@ -J$(MOD_DIR)
$(MOD_DIR)/%.o: $(vortZ2D_DIR)/%.f90 | $(MOD_DIR)
    $(FC) $(FFLAGS) $(OBJ) -o $(TAR1) ../vortZ2D.f90 -J$(MOD_DIR)

runner: $(OBJ) $(OBJ1)

clean:
    @if [ -d $(MOD_DIR) ]; then \
        rm -rf $(MOD_DIR) && echo "build/ cleaned"; \
    else \
        echo "nothing to clean"; \
    fi
run:
    @"make; ./vortZ2D; cd ../bin"

我有一个Makefile在/bin文件夹中。当/oop中的源文件被更新时,不会触发级联。如果需要,您可以包含-fsyntax-only标志来加速。希望这可以帮助到你。

你在这个文件中有一个问题。在.o或.mod文件(模块所在的地方)中,你完全没有依赖关系,因此如果你通过向子程序添加变量或更改模块之间传递的数组的维度来更改源文件,可能会发生意外情况,或者在链接步骤中出现错误,我不确定。如果你没有模块,那么一切都很好,但对于我的问题来说不适用。不过,我以前不知道在makfiles中有管道命令,谢谢你告诉我! - Jonatan Öström
模块实际上是相互依存的。但是如果例如在一个模块中更改了任何变量,链接器步骤中将会出现错误。但这其实也没什么,因为这只是发现错误传播的方式。 - b-fg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接