在 Fortran90 中,是否可以在主程序中使用文件中的模块?

In Fortran90, is it possible to use a module from a file with a main program?

我继承了一些我不想编辑的遗留 Fortran90 代码。文件 main.f90 有一个模块,其中包含一些我想在我自己的程序中使用的子例程,但也有一个主程序。它看起来像这样:

module libmain
    implicit none
    contains
    subroutine dostuff
        print *,'m'
    end subroutine dostuff
end module libmain

program main
    use libmain
    implicit none
    call dostuff
end program main

我想在文件 myprogram.f90 中的我自己的程序中使用模块 libmain,如下所示:

program myprogram
    use libmain
    implicit none
    call dostuff
end program myprogram

我已尽我所能来完成这项工作。例如:

>gfortran -c main.f90
>gfortran -c myprogram.f90
>gfortran -o myprogram main.o myprogram.o

失败并出现错误:

duplicate symbol '_main' in:
    main.o
    myprogram.o
ld: 1 duplicate symbol for architecture x86_64
collect2: error: ld returned 1 exit status

我尝试将 main.o 排除在最终 linking 的参数之外,但这也失败了:

>gfortran -o myprogram myprogram.f90
Undefined symbols for architecture x86_64:
  "___libmain_MOD_dostuff", referenced from:
      _MAIN__ in myprogram.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

有趣的是,如果我删除文件 main.olibmain.mod,,我会得到一个不同的错误:

>rm main.o
>rm libmain.mod
>gfortran -o myprogram myprogram.f90
myprogram.f90:2:8:

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

所以 gfortran 知道它应该寻找 libmain.mod 文件,即使当我尝试 link myprogram.。那么为什么 gfortran 找不到符号 dostuff 呢?它显然知道在哪里可以找到文件libmain.mod,这不是问题。

编辑:我尝试了更多技巧,none 成功了。

我想也许问题是 gfortran 期望 .o.mod 文件具有相同的名称,所以我重命名为:

>mv main.o libmain.o
>gfortran -o myprogram myprogram.f90

Undefined symbols for architecture x86_64:
  "___libmain_MOD_dostuff", referenced from:
      _MAIN__ in ccmD6cx3.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

所以这也行不通。我也尝试了另一种方式,将 libmain.mod 移动到 main.mod:

>rm *.mod
>rm *.o
>gfortran -c main.f90
>gfortran -c myprogram.f90
>mv libmain.mod main.mod
>gfortran -o myprogram myprogram.o
Undefined symbols for architecture x86_64:
  "___libmain_MOD_dostuff", referenced from:
      _MAIN__ in myprogram.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

如果我在编译前进行重命名 myprogram.f90:

>rm *.mod
>rm *.o
>gfortran -c main.f90
>mv libmain.mod main.mod
>gfortran -c myprogram.f90
myprogram.f90:2:8:

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

所以我也更改了 myprogram.f90 中对 main 的引用:

program myprogram
    use main
    implicit none
    call dostuff
end program myprogram

同时保持 main.f90 不变。现在我执行以下步骤(从头开始):

>rm *.mod
>rm *.o
>gfortran -c main.f90
>mv libmain.mod main.mod
>gfortran -c myprogram.f90 
>gfortran -o myprogram myprogram.o
Undefined symbols for architecture x86_64:
  "___libmain_MOD_dostuff", referenced from:
      _MAIN__ in myprogram.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status

这样就修复了文件引用错误,但我仍然没有得到我需要的符号。

你不能有两个程序。在 Fortran 中是不允许的。

如果您想使用 module,您可以将它复制到一个不同的单独的源文件,没有旧程序,或者在现有文件中注释掉旧程序。

您不能link同时使用两个程序。

您尝试过的那些技巧只是转移注意力,请勿尝试使用 .mod 文件或任何东西。只是以某种方式从编译链中删除旧程序。

我理解你的痛苦,伙计。尽管已经发布的答案是您可以获得的最佳建议,但如果您正在处理遗留的、真正遗留的代码,它并不能解决您的问题。

让我们尝试破解它一点。假设您有遗留代码(您可能处于甚至无法访问源代码的情况)。

! a.f90
module libmain
    implicit none
    contains
    subroutine dostuff
        print *,'m'
    end subroutine dostuff
end module libmain

program main
    use libmain
    implicit none
    call dostuff
end program main

并且,假设这是您的全新 _main

! b.f90
program myprogram
    use libmain
    implicit none
    print *,'Hello from b'
    call dostuff
end program myprogram

现在,让我们用这些令人讨厌的 _main 符号解决您的问题。

> gfortran-8.3.0 -c a.f90
> objcopy -W _main a.o  # Force symbol _main to be marked as a weak
> gfortran-8.3.0 -c b.f90
> gfortran-8.3.0 -o main a.o b.o
> ./main
 Hello from b
 m

瞧瞧!

P.S.

请注意,这是一个 hack,您可能会遇到很多副作用,尤其是在您的原始代码设置了一些全局变量、进行了一些初始化等的情况下。因此,请谨慎使用这种方法。