清除在Fortran 90中将函数/子例程声明与定义分开的方法

时间:2015-01-16 13:00:33

标签: makefile fortran fortran90 fortran95

我正在开发一个包含大量模块的大型Fortran 90代码。困扰我的是,当我修改模块内部函数的内部代码(不更改其掩码)时,我的Makefile(其依赖项基于“use”)重新编译“使用”该修改模块的每个文件,并递归。

但是当修改函数的内部代码而不触及其输入/输出时,重新编译除修改后的文件之外的其他文件是没用的,不是吗?

所以我想将函数声明与它们的定义分开,就像在C或C ++中使用.h文件一样。干净的方法是什么?我是否必须使用Fortran包含/预处理器#include,或者是否有“模块/使用”方式来执行此操作?

我尝试过这样的事情,但这似乎是无稽之谈......

main.f90时

program prog

  use foomod_header

  integer :: i

  bar=0
  i=42
  call foosub(i)

end program prog

foomod_header.f90

module foomod_header

  integer :: bar

  interface 
    subroutine foosub(i)
      integer :: i
    end subroutine
  end interface

end module foomod_header

foomod.f90

module foomod

  use foomod_header

  contains

  subroutine foosub(i)
    integer ::i

    print *,i+bar

  end subroutine foosub

end module foomod

2 个答案:

答案 0 :(得分:2)

如果子模块不是一个选项(并且它们是理想的选项),那么您可以做的是使该过程成为外部过程并为模块中的该过程提供接口。例如:

! Program.f90
PROGRAM p
  USE Interfaces
  IMPLICIT NONE
  ...
  CALL SomeProcedure(xyz)
END PROGRAM p

! Interfaces.f90
MODULE Interfaces
  IMPLICIT NONE
  INTERFACE
    SUBROUTINE SomeProcedure(some_arg)
      USE SomeOtherModule
      IMPLICIT NONE
      TYPE(SomeType) :: some_arg
    END SUBROUTINE SomeProcedure
  END INTERFACE
END MODULE Interfaces

! SomeProcedure.f90
SUBROUTINE SomeProcedure(some_arg)
  USE SomeOtherModule
  IMPLICIT NONE
  TYPE(SomeType) :: some_arg
  ...
END SUBROUTINE SomeProcedure

一些重要的注释:

  • 对于在作用域中可访问的过程,必须只有一个接口定义。在子程序内部,子程序定义的过程的接口也被认为是定义的 - 因此在子程序中,您不能允许接口块用于子程序定义的过程。就示例而言,这意味着在USE Interfaces外部过程中没有唯一子句时,您不能拥有SomeProcedure语句。

  • 如果您确实更改了SomeProcedure.f90中的过程或类似过程,您最好确保更改模块内的相应接口块!

  • 如果您可以使用F2003,IMPORT语句可以让生活更轻松。否则,您可能必须具有其他模块(例如示例中的SomeOtherModule)以在Interfaces模块和外部过程之间共享类型定义等。

  • 如果您拥有与该过程相关的私有实体或组件,那么Fortran的规则实体和组件可访问性可能会阻止您使用此方法。

  • 通常,某种程序的整体程序分析是在高水平的优化下完成的。该分析通常比实际解析代码慢得多 - 以这种方式拆分过程实际上可能不会在这些条件下显着缩短构建时间。

答案 1 :(得分:0)

也许最干净的解决方案是更改构建系统。

USE语句引入的实际依赖关系不是源代码文件,而是生成的.mod文件,它充当一种“二进制头文件”。即Makefile通常包含类似

的内容
MyProgram.o: MyModule.f90

它们真正应该包含的是

MyProgram.o: MyModule.mod
MyModule.mod: MyModule.f90

.mod文件的创建以某种方式完成,如果接口没有实际更改,则可以确保文件系统时间戳不变。

可悲的是,编译器支持很尴尬。大多数编译器无论如何都会覆盖.mod文件,因此构建过程必须同时检测.mod文件没有更改,例如。通过在内容不变的情况下恢复旧的修改时间,但同时又需要避免不必要地重新编译源文件,这需要更新.mod文件的修改时间。

此外,某些编译器(Intel,* cough *)向.mod文件的 contents 添加了二进制时间戳,需要手动将它们从比较中排除,并具有跨发行版更改了二进制位置。在支持多个编译器时,这会增加工作量。