4

我正在使用 gfortran 的 95+ 扩展。我有一个实用模块库,我想链接到其他项目,即作为库或共享对象/dll。但是,在 Fortran 中,我不明白如何在不维护模块接口的两个副本的情况下将接口与 Fortran 中的实现分开。

在 C 中,我会将接口与实现分开,例如:

 api.h ←includes← impl.h
   ↑                 ↑
includes          includes
   ↑                 ↑
 user.c           impl.c

有没有办法在现代 Fortran 中实现相同的效果?我是否需要向我的库中的用户提供 .mod 文件?

  • 显式接口的单一定义
  • 只有接口定义暴露给用户代码

编辑:总结(我认为是)答案:

  • 需要 .mod 文件,因为它们包含显式接口定义

  • 模块没有标准的 Fortran ABI——.mod 文件将是特定于编译器的

  • 实现隐藏问题的唯一直接类似方法是子模块,它在 Fortran 2008 中定义,gfortran 不支持。

  • 除了 @High-Performance-Mark 和 Fedora 页面指出的避免模块之外,最实用的方法是分发仅接口模块的包含文件以及用于实现的预编译 .mods。

  • 使用包含有一些众所周知且令人讨厌的问题,包括可能重新定义常见块。

我有点惊讶这里实际上没有一个简单的答案。

4

3 回答 3

5

我相信您可以使用 Fortran 2008 编译器对子模块执行此操作。来自 FortranWiki:

子模块是 Fortran 2008 的一项功能,它允许模块过程在模块中定义其接口,同时在单独的单元(子模块)中定义过程的主体。

来自维基百科(重点是我的)

[子模块允许] 模块的规范和实现以单独的程序单元表示,这改进了大型库的打包,允许在发布权威接口的同时保留商业机密,并防止编译级联。

我对子模块没有任何经验,它们还没有得到广泛的支持,但它们是需要注意的。

编辑由于许多编译器不支持子模块,因此讨论其他选项可能会有所帮助。

此页面提出了与此类似的问题,并且有许多不错的链接。在关于 Google 群组的讨论中特别有用(请特别参阅这篇文章)。总之,一种选择是:

  • 将所有库函数/子例程分组到一个文件中并单独分组(即不是模块的一部分)。

  • 创建一个模块,该模块仅包含您想要向最终用户公开的那些子例程的接口。

  • 为最终用户提供编译后的模块和库。然后,用户可以use在他/她的程序中使用该模块并链接到库。

这允许您“隐藏”您不想向最终用户公开的函数/子例程。

从我链接到的帖子中提取:

一些编译器会生成一个 .mod(或编译器赋予它的任何名称)文件和一个库文件。.mod 文件有符号;库文件包含模块中包含的可执行代码。在这种情况下,您必须将这两个文件分发给您的最终用户。

此外,一些编译器(特别是 f95)将符号和可执行代码放入单个 .mod 文件中。在这种情况下,您只需向最终用户提供 .mod 文件。

(最终!)编辑Fedora wiki 上有一个有用的页面:

理想情况下,可移植的 Fortran 库会避免使用模块。好消息是已经定义了一个子模块规范,它允许模块的接口规范部分与过程源代码分开。On[c]e 这是在 Fortran 编译器中实现的,它应该被所有打包的库使用。

于 2012-05-31T13:39:16.697 回答
2

另一种将接口与实现分离并且只编写一次的方法,自 FORTRAN77 以来(甚至可能在此之前)已被广泛使用的方法是使用INCLUDE一行将一个源文件的文本包含到另一个源文件中。避免 INCLUDE 有很多合理的软件工程原因,并且在使用它们方面有很多实际用途。

我应该补充一点,我喜欢 Chris 已经概述的方法,而不是诉诸 INCLUDE,但有时需要必须......

于 2012-05-31T14:01:03.090 回答
2

这取决于你想做什么。如果出于商业机密的目的是为了向人们隐藏代码,您可以编写“接口”并提供预编译的库而不是实际代码。用户将使用接口编译文件,以便能够调用您的程序。

如果您只想练习仅公开必要内容的良好编程实践,您可以使用模块并通过将它们指定为“私有”来指定模块内部的一些过程或模块变量。人们可以使用编辑器查看代码,但在模块之外无法调用过程。您只能向程序的其余部分披露应该使用的程序并隐藏其他程序。您可以使用模块顶部的私有语句将“私有”设置为默认值,并指定需要在“公共”语句中可见的过程。

除非您不希望您的用户看到或编译您的源代码,否则我不会提供 .mod 文件。这就产生了支持各种编译器而不是简单地提供源代码的问题。“private”和“public”语句应该实现您的两个目标,即不重复接口定义和只公开您希望公开的接口。除非您的程序非常大或存在其他问题,否则其他方法对我来说似乎过于复杂。

于 2012-05-31T16:00:39.140 回答