为Fortran 90生成的Makefile会导致未解析的外部符号

时间:2016-07-27 15:42:43

标签: makefile fortran fortran90

我的程序是一个使用intel MKL的mpi程序。简单来说,我们假设有main.f90 a.f90 b.f90 a.f90包含其他人需要的模块mymod

通常我会像这样编译它

mpiifort *90 /fast /Qmkl /MD -o main.exe

我只是做了两次,因为这是第一次缺少mymod.mod

现在我想使用makefile,因为我想减少重新编译时间。我这样写的

IFORT = /fast
MKL =/Qmkl
LDFLAGS = /MD
main:main.obj b.obj
    mpiifort $(IFORT) $(MKL) $(LDFLAGS) $< -o $@
mymod.mod:a.f90
    mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
main.obj:main.f90
    mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
b.obj:b.f90
    mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<

但是,这里肯定有问题。我有一堆unresolved external symbol。有什么问题?

2 个答案:

答案 0 :(得分:0)

首先,其他人可能会写一个更好/更完整的答案(或指示我们一个),我会欢迎这一点,但在下面我提供了一个非常简单的例子。

现在我们可以识别错误的(可能的)来源:如果我们用touch替换编译命令,我们可以生成一个演示问题的简单示例

main:main.obj b.obj
        touch $@
mymod.mod:a.f90
        touch $@
main.obj:main.f90
        touch $@
b.obj:b.f90
        touch $@

如果我们用

构建我们的“源文件”
>touch main.f90 b.f90 a.f90

然后我们可以尝试构建我们的main可执行文件:

>make main

将输出:

touch main.obj 
touch b.obj
touch main

请注意,这不会创建mymod.mod文件。这意味着在您的情况下a.f90在构建main时不会被编译,因此所需的symobols不可用(即,当链接时,函数/例程等未定义为{{1} }不可用)。如果我们现在通过将makefile调整为

来显示a.obj取决于main
mymod.mod

我们现在可以尝试构建main:main.obj b.obj mymod.mod touch $@ mymod.mod:a.f90 touch $@ main.obj:main.f90 touch $@ b.obj:b.f90 touch $@ (在通过main首次清理后),我们得到:

rm *.obj mymod.mod main

因此,我们已成功获得>make main touch main.obj touch b.obj touch mymod.mod touch main 来构建make目标作为构建mymod.mod的一部分。请注意,实际上您可能希望确保某些目标在其他目标之前构建(例如,您可能希望在main之前编译a.f90)。您可以使用依赖项列表执行此操作,您可能希望自动生成(请参阅例如this question)。

答案 1 :(得分:0)

如果我们使用intel fortran,我会想出一种自动的方法

英特尔fortran提供了一个名为gen-dep的选项,它会自动分析并输出可用于makefile的依赖信息。所以只需运行以下命令,如果由于缺少mod文件而出现错误消息,则只需运行两次

mpiifort *90 /Qmkl /gen-dep > dependency.txt

我们得到了dependency.txt。打开它,我们会找到类似这样的东西

mpifc.bat for the Intel(R) MPI Library 5.1.2 for Windows*
Copyright(C) 2007-2015, Intel Corporation. All rights reserved.

mymod.mod : \
  a.f90

a.obj : \
  a.f90

b.obj : \
  b.f90 mymod.mod

main.obj : \
  main.f90 \
  c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\include\mpi_base.mod \
  c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\include\mpi_sizeofs.mod \
  c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\include\mpi_constants.mod \
  c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\include\mpi.mod \
  mymod.mod

Microsoft (R) Incremental Linker Version 14.00.23026.0
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:a.exe 
-subsystem:console 
"-libpath:c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mkl\lib\intel64_win" 
"/LIBPATH:c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\lib\release_mt" 
"/LIBPATH:c:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2016.1.146\windows\mpi\intel64\bin\..\..\intel64\lib" 
impi.lib 
a.obj 
b.obj 
main.obj 

那些与mpi相关的模块是静态的,所以只需将其删除即可。经过一些简单的文本操作(使用正则表达式将是一个不错的选择),使其更清晰和紧凑,我们可以得到一个像这样的正确的makefile(我在我的问题帖子中修复了一些错误)

IFORT = /fast
MKL =/Qmkl
LDFLAGS = /MD
a: a.obj b.obj main.obj 
    mpiifort $(IFORT) $(MKL) $(LDFLAGS) $^ -o $@.exe
mymod.mod : a.f90
    mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
a.obj : a.f90
    mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
b.obj : b.f90 mymod.mod
    mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<
main.obj : main.f90 mymod.mod
    mpiifort /c $(IFORT) $(MKL) $(LDFLAGS) $<