【问题标题】:How to provide an explicit interface to a library of Fortran 95+ modules, with implementation hiding如何为 Fortran 95+ 模块库提供显式接口,并隐藏实现
【发布时间】:2012-05-31 13:15:12
【问题描述】:

我正在使用 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。

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

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

【问题讨论】:

    标签: fortran gfortran fortran95


    【解决方案1】:

    我相信您可以通过使用 Fortran 2008 编译器的 submodules 来做到这一点。来自 FortranWiki:

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

    来自Wikipedia(强调我的)

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

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

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

    This page 提出了与此类似的问题,并且有许多不错的链接。在关于 Google 群组的讨论中特别有用(尤其请参阅 this post)。总之,一种选择是:

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

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

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

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

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

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

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

    (最终!)编辑 Fedora wiki 上有一个useful page

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多